From f4d083bf64d1a2b4f603d0f5fa96f3ac4e7db1fe Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 4 Jan 2021 19:51:38 +0100 Subject: Add run command, remove colored text output if output is redirected to file --- backend/ninja/Ninja.cpp | 17 ++++++-- src/Exec.cpp | 2 +- src/main.cpp | 107 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 96 insertions(+), 30 deletions(-) diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 8b815cb..fad1d35 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -12,6 +12,7 @@ using namespace std; using namespace sibs; #if OS_FAMILY == OS_FAMILY_POSIX +#include #define nprintf printf #else #define nprintf wprintf @@ -1889,9 +1890,19 @@ namespace backend Result Ninja::compile(const _tinydir_char_t *buildFilePath) { #if OS_TYPE == OS_TYPE_LINUX - FileString command = TINYDIR_STRING("script -eqc 'ninja -C \""); - command += buildFilePath; - command += TINYDIR_STRING("\"' /dev/null"); + FileString command; + if(isatty(STDOUT_FILENO) == 1) + { + command = TINYDIR_STRING("script -eqc 'ninja -C \""); + command += buildFilePath; + command += TINYDIR_STRING("\"' /dev/null"); + } + else + { + command = TINYDIR_STRING("ninja -C \""); + command += buildFilePath; + command += TINYDIR_STRING("\""); + } #else FileString command = TINYDIR_STRING("ninja -C \""); command += buildFilePath; diff --git a/src/Exec.cpp b/src/Exec.cpp index cc82897..169858f 100644 --- a/src/Exec.cpp +++ b/src/Exec.cpp @@ -7,7 +7,7 @@ using namespace std; -const int BUFSIZE = 1024; +const int BUFSIZE = 4096; // TODO: Redirect stderr to namespace sibs diff --git a/src/main.cpp b/src/main.cpp index cc1f4a5..8282889 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,6 +118,7 @@ static void usage() printf("Simple Build System for Native Languages\n\n"); printf("Commands:\n"); printf(" build Build a project that contains a project.conf file\n"); + printf(" run Build and run a project that contains a project.conf file\n"); printf(" new Create a new project\n"); printf(" init Initialize project in an existing directory\n"); printf(" test Build and run tests for a sibs project\n"); @@ -127,22 +128,24 @@ static void usage() exit(1); } -static void usageBuild() +static void usageBuild(bool run) { - printf("Usage: sibs build [project_path] [--debug|--release] [--sanitize=(address|undefined|leak|thread|none)] [--platform ]\n\n"); - printf("Build a sibs project\n\n"); + printf("Usage: sibs %s [project_path] [--debug|--release] [--sanitize=(address|undefined|leak|thread|none)] [--platform ]\n\n", run ? "run" : "build"); + printf("%s a sibs project\n\n", run ? "Build and run" : "Build"); printf("Options:\n"); printf(" project_path The directory containing a project.conf file - Optional (default: current directory)\n"); printf(" --debug|--release Optimization level to build project and dependencies with (if not a system package) - Optional (default: --debug)\n"); printf(" --sanitize Add runtime address/undefined behavior sanitization. Program can be up to 3 times slower and use 10 times as much RAM. Ignored if compiler doesn't support sanitization - Optional (default: none)\n"); printf(" --platform The platform to build for - Optional (default: the running platform)\n"); printf("Examples:\n"); - printf(" sibs build\n"); - printf(" sibs build dirA/dirB\n"); - printf(" sibs build --release\n"); - printf(" sibs build dirA --release\n"); - printf(" sibs build --sanitize=address\n"); - printf(" sibs build --release --platform win64\n"); + printf(" sibs %s\n", run ? "run" : "build"); + if(run) + printf(" sibs run --args hello world\n"); + printf(" sibs %s dirA/dirB\n", run ? "run" : "build"); + printf(" sibs %s --release\n", run ? "run" : "build"); + printf(" sibs %s dirA --release\n", run ? "run" : "build"); + printf(" sibs %s --sanitize=address\n", run ? "run" : "build"); + printf(" sibs %s --release --platform win64\n", run ? "run" : "build"); exit(1); } @@ -359,7 +362,7 @@ static void appendBuildToolToPathEnv() #endif } -static int buildProject(const FileString &projectPath, const FileString &projectConfFilePath, SibsConfig &sibsConfig) +static int buildProject(const FileString &projectPath, const FileString &projectConfFilePath, SibsConfig &sibsConfig, bool run, FileString run_args) { FileString buildPath; readSibsConfig(projectPath, projectConfFilePath, sibsConfig, buildPath); @@ -375,7 +378,7 @@ static int buildProject(const FileString &projectPath, const FileString &project sibsConfig.setPackageType(PackageType::DYNAMIC); } - auto startTime = high_resolution_clock::now(); + auto startTime = steady_clock::now(); if(sibsConfig.shouldUseCmake()) { auto dummyCallback = [](const string&){}; @@ -444,12 +447,53 @@ static int buildProject(const FileString &projectPath, const FileString &project exit(7); } } - auto elapsedTime = duration_cast>(high_resolution_clock::now() - startTime); - printf("Finished in %fs\n", elapsedTime.count()); + auto elapsedTime = duration_cast>(steady_clock::now() - startTime); + printf("Finished building in %fs\n", elapsedTime.count()); + + if(run) { + FileString executableName = toFileString(sibsConfig.getPackageName()); + if(isSamePlatformFamily(sibsConfig.platform, PLATFORM_WIN)) + executableName += TINYDIR_STRING(".exe"); + auto exec_result = exec(buildPath + TINYDIR_STRING("/") + executableName + TINYDIR_STRING(" ") + run_args, true); + if(!exec_result) { + ferr << "Failed to execute" << (buildPath + TINYDIR_STRING("/") + executableName) << ", error: " << toFileString(exec_result.getErrMsg()) << endl; + return 1; + } + return exec_result.getErrorCode(); + } return 0; } +#if OS_FAMILY == OS_FAMILY_WINDOWS +#define NATIVE_CHAR_PREFIX L +#else +#define NATIVE_CHAR_PREFIX +#endif + +static FileString replace_all(const _tinydir_char_t *str) { + FileString result = TINYDIR_STRING("'"); + while(*str != NATIVE_CHAR_PREFIX'\0') { + if(*str == NATIVE_CHAR_PREFIX'\'') + result += TINYDIR_STRING("\\'"); + else + result += *str; + ++str; + } + result += NATIVE_CHAR_PREFIX'\''; + return result; +} + +static FileString escape_args(const std::vector &args) { + FileString result; + for(const _tinydir_char_t *arg : args) { + if(!result.empty()) + result += NATIVE_CHAR_PREFIX' '; + result += replace_all(arg); + } + return result; +} + static Sanitize sanitize_string_to_type(const _tinydir_char_t *str) { if(strcmp(str, TINYDIR_STRING("address")) == 0) return Sanitize::ADDRESS; @@ -465,12 +509,13 @@ static Sanitize sanitize_string_to_type(const _tinydir_char_t *str) { return SANITIZE_INVALID; } -static int buildProject(int argc, const _tinydir_char_t **argv) +static int buildProject(int argc, const _tinydir_char_t **argv, bool run) { OptimizationLevel optimizationLevel = OPT_LEV_NONE; FileString projectPath; Sanitize sanitize = Sanitize::NONE; FileString platformName; + std::vector run_args; for(int i = 0; i < argc; ++i) { @@ -480,7 +525,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv) if(optimizationLevel != OPT_LEV_NONE) { ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as debug" << endl; - usageBuild(); + usageBuild(run); } optimizationLevel = OPT_LEV_DEBUG; } @@ -489,7 +534,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv) if(optimizationLevel != OPT_LEV_NONE) { ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as release" << endl; - usageBuild(); + usageBuild(run); } optimizationLevel = OPT_LEV_RELEASE; } @@ -498,7 +543,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv) sanitize = sanitize_string_to_type(arg + 11); if(sanitize == SANITIZE_INVALID) { ferr << "Error: Invalid sanitize option " << (arg + 11) << ", expected address, undefined, leak, thread or none" << endl; - usageBuild(); + usageBuild(run); } } else if(_tinydir_strcmp(arg, TINYDIR_STRING("--platform")) == 0) @@ -506,7 +551,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv) if(i == argc - 1) { ferr << "Error: Expected platform to target after --platform" << endl; - usageBuild(); + usageBuild(run); } ++i; @@ -515,21 +560,26 @@ static int buildProject(int argc, const _tinydir_char_t **argv) if(!platformName.empty()) { ferr << "Error: Platform defined twice. First as " << platformName << " then as " << arg << endl; - usageBuild(); + usageBuild(run); } platformName = arg; } + else if(run && _tinydir_strcmp(arg, TINYDIR_STRING("--args")) == 0) + { + run_args.insert(run_args.end(), argv + i + 1, argv + argc); + break; + } else if(_tinydir_strncmp(arg, TINYDIR_STRING("--"), 2) == 0) { ferr << "Error: Invalid argument " << arg << endl; - usageBuild(); + usageBuild(run); } else { if(!projectPath.empty()) { ferr << "Error: Project path was defined more than once. First defined as " << projectPath << " then as " << arg << endl; - usageBuild(); + usageBuild(run); } projectPath = arg; } @@ -547,7 +597,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv) { ferr << "Invalid platform " << platformName << endl; ferr << "Expected one of: " << getPlatformListFormatted() << std::endl; - usageBuild(); + usageBuild(run); } bool crossCompileLinux64ToWin64 = (SYSTEM_PLATFORM == PLATFORM_LINUX_X86_64 && platform == PLATFORM_WIN64); @@ -595,7 +645,7 @@ static int buildProject(int argc, const _tinydir_char_t **argv) sibsConfig.showWarnings = true; sibsConfig.platform = platform; sibsConfig.setSanitize(sanitize); - return buildProject(projectPath, projectConfFilePath, sibsConfig); + return buildProject(projectPath, projectConfFilePath, sibsConfig, run, escape_args(run_args)); } static int testProject(int argc, const _tinydir_char_t **argv) @@ -740,7 +790,7 @@ static int testProject(int argc, const _tinydir_char_t **argv) sibsConfig.zigTestFiles = move(filesToTest); sibsConfig.zigTestAllFiles = testAllFiles; - return buildProject(projectPath, projectConfFilePath, sibsConfig); + return buildProject(projectPath, projectConfFilePath, sibsConfig, false, TINYDIR_STRING("")); } // Returns nullptr if @charToFind is not found @@ -1178,7 +1228,7 @@ static int packageProject(int argc, const _tinydir_char_t **argv) sibsConfig.showWarnings = true; sibsConfig.packaging = packagingType == PackagingType::STATIC; sibsConfig.bundling = (packagingType == PackagingType::BUNDLE) || (packagingType == PackagingType::BUNDLE_INSTALL); - int result = buildProject(projectPath, projectConfFilePath, sibsConfig); + int result = buildProject(projectPath, projectConfFilePath, sibsConfig, false, TINYDIR_STRING("")); if(result != 0) return result; @@ -1438,7 +1488,12 @@ int wmain(int argc, const _tinydir_char_t **argv) if(_tinydir_strcmp(arg, TINYDIR_STRING("build")) == 0) { appendBuildToolToPathEnv(); - return buildProject(subCommandArgCount, subCommandArgPtr); + return buildProject(subCommandArgCount, subCommandArgPtr, false); + } + else if(_tinydir_strcmp(arg, TINYDIR_STRING("run")) == 0) + { + appendBuildToolToPathEnv(); + return buildProject(subCommandArgCount, subCommandArgPtr, true); } else if(_tinydir_strcmp(arg, TINYDIR_STRING("new")) == 0) { -- cgit v1.2.3