Add command line arguments (--chdir/--debug, ...)

This commit is contained in:
Luke Street 2025-09-28 18:43:09 -06:00
parent fd47411fff
commit 3d22538590
3 changed files with 95 additions and 19 deletions

View File

@ -9,7 +9,7 @@
## Build, Test, and Development Commands
- `cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON` configures a 32-bit toolchain; ensure multilib packages are present.
- `cmake --build build --target wibo` compiles the shim; switch to `-DCMAKE_BUILD_TYPE=Release` for optimised binaries.
- `./build/wibo /path/to/program.exe` runs a Windows binary through the shim; use `WIBO_DEBUG=1` for verbose logging.
- `./build/wibo /path/to/program.exe` runs a Windows binary. Use `WIBO_DEBUG=1` (or `--debug`/`-D`) for verbose logging. Use `--chdir`/`-C` to set the working directory.
- `cmake -B build -DBUILD_TESTING=ON` + `ctest --test-dir build --output-on-failure` runs the self-checking WinAPI fixtures (requires `i686-w64-mingw32-gcc` and `i686-w64-mingw32-windres`).
- `clang-format -i path/to/file.cpp` and `clang-tidy path/to/file.cpp -p build` keep contributions aligned with the repo's tooling.
- DON'T use `clang-format` on existing files, only new or heavily modified ones; the repo hasn't been fully formatted yet.

View File

@ -16,11 +16,16 @@ cmake --build build --target wibo
## Running
```sh
./build/wibo /path/to/program.exe
# or, with debug logging:
WIBO_DEBUG=1 ./build/wibo /path/to/program.exe
./build/wibo /path/to/program.exe [arguments...]
```
Supported command line options:
- `--help`: Print usage information.
- `-D`, `--debug`: Enable shim debug logging (equivalent to `WIBO_DEBUG=1`).
- `-C DIR`, `--chdir DIR`, `--chdir=DIR`: Change to `DIR` before running the program.
- `--`: Stop option parsing; following arguments are interpreted as the program command line.
## Tests
Self-checking Windows fixtures run through CTest. They require a 32-bit MinGW cross toolchain (`i686-w64-mingw32-gcc` and `i686-w64-mingw32-windres`).
@ -40,8 +45,6 @@ This will cross-compile the fixture executables, run them through `wibo`, and fa
Rough to-do list:
- Implement more APIs
- Do something intelligent with Windows `HANDLE`s
- Convert paths in environment variables (and the structure of `PATH` itself, maybe) to Windows format
---

View File

@ -3,12 +3,14 @@
#include "strutil.h"
#include <asm/ldt.h>
#include <charconv>
#include <cstring>
#include <fcntl.h>
#include <filesystem>
#include <memory>
#include <stdarg.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <vector>
uint32_t wibo::lastError = 0;
@ -84,6 +86,18 @@ TIB tib;
const size_t MAPS_BUFFER_SIZE = 0x10000;
static void printHelp(const char *argv0) {
std::filesystem::path exePath(argv0 ? argv0 : "wibo");
std::string exeName = exePath.filename().string();
fprintf(stdout, "Usage: %s [options] <program.exe> [arguments...]\n", exeName.c_str());
fprintf(stdout, "\n");
fprintf(stdout, "Options:\n");
fprintf(stdout, " --help\t\tShow this help message and exit\n");
fprintf(stdout, " -C, --chdir DIR\tChange working directory before launching the program\n");
fprintf(stdout, " -D, --debug\tEnable shim debug logging (same as WIBO_DEBUG=1)\n");
fprintf(stdout, " --\t\tStop option parsing; following arguments are interpreted as the program command line\n");
}
/**
* Read /proc/self/maps into a buffer.
*
@ -186,17 +200,73 @@ static void blockUpper2GB() {
}
int main(int argc, char **argv) {
if (argc <= 1) {
printf("Usage: ./wibo program.exe ...\n");
return 1;
std::string chdirPath;
bool optionDebug = false;
bool parsingOptions = true;
int programIndex = -1;
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (parsingOptions) {
if (strcmp(arg, "--") == 0) {
parsingOptions = false;
continue;
}
if (strcmp(arg, "--help") == 0) {
printHelp(argv[0]);
return 0;
}
if (strcmp(arg, "-D") == 0 || strcmp(arg, "--debug") == 0) {
optionDebug = true;
continue;
}
if (strncmp(arg, "--chdir=", 8) == 0) {
chdirPath = arg + 8;
continue;
}
if (strcmp(arg, "-C") == 0 || strcmp(arg, "--chdir") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "Option %s requires a directory argument\n", arg);
return 1;
}
chdirPath = argv[++i];
continue;
}
if (strncmp(arg, "-C", 2) == 0 && arg[2] != '\0') {
chdirPath = arg + 2;
continue;
}
if (arg[0] == '-' && arg[1] != '\0') {
fprintf(stderr, "Unknown option: %s\n", arg);
fprintf(stderr, "\n");
printHelp(argv[0]);
return 1;
}
}
programIndex = i;
break;
}
if (getenv("WIBO_DEBUG")) {
if (programIndex == -1) {
printHelp(argv[0]);
return argc <= 1 ? 0 : 1;
}
if (!chdirPath.empty()) {
if (chdir(chdirPath.c_str()) != 0) {
std::string message = std::string("Failed to chdir to ") + chdirPath;
perror(message.c_str());
return 1;
}
}
if (optionDebug || getenv("WIBO_DEBUG")) {
wibo::debugEnabled = true;
}
if (getenv("WIBO_DEBUG_INDENT")) {
wibo::debugIndent = std::stoul(getenv("WIBO_DEBUG_INDENT"));
if (const char *debugIndentEnv = getenv("WIBO_DEBUG_INDENT")) {
wibo::debugIndent = std::stoul(debugIndentEnv);
}
blockUpper2GB();
@ -226,15 +296,18 @@ int main(int argc, char **argv) {
wibo::tibSelector = static_cast<uint16_t>((tibDesc.entry_number << 3) | 7);
char **guestArgv = argv + programIndex;
int guestArgc = argc - programIndex;
// Build a command line
std::string cmdLine;
for (int i = 1; i < argc; i++) {
for (int i = 0; i < guestArgc; ++i) {
std::string arg;
if (i == 1) {
arg = files::pathToWindows(std::filesystem::absolute(argv[1]));
if (i == 0) {
arg = files::pathToWindows(std::filesystem::absolute(guestArgv[0]));
} else {
cmdLine += ' ';
arg = argv[i];
arg = guestArgv[i];
}
bool needQuotes = arg.find_first_of("\\\" \t\n") != std::string::npos;
if (needQuotes)
@ -271,15 +344,15 @@ int main(int argc, char **argv) {
DEBUG_LOG("Command line: %s\n", wibo::commandLine);
wibo::executableName = argv[0];
wibo::argv = argv + 1;
wibo::argc = argc - 1;
wibo::argv = guestArgv;
wibo::argc = guestArgc;
wibo::initializeModuleRegistry();
wibo::Executable exec;
wibo::mainModule = &exec;
char* pe_path = argv[1];
char* pe_path = guestArgv[0];
FILE *f = fopen(pe_path, "rb");
if (!f) {
std::string mesg = std::string("Failed to open file ") + pe_path;