diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 160 |
1 files changed, 91 insertions, 69 deletions
diff --git a/src/main.cpp b/src/main.cpp index 0f20ea0..f49ba59 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,6 +20,12 @@ using namespace sibs; // TODO: Places that use PATH_MAX should be modified. A path CAN be longer than PATH_MAX... (does this include replacing tinydir.h?) +#if OS_FAMILY == OS_FAMILY_POSIX +#define ferr std::cerr +#else +#define ferr std::wcerr +#endif + void usage() { printf("Usage: sibs COMMAND\n\n"); @@ -59,47 +65,47 @@ void usageNew() exit(1); } -void validateDirectoryPath(const char *projectPath) +void validateDirectoryPath(const _tinydir_char_t *projectPath) { FileType projectPathFileType = getFileType(projectPath); if(projectPathFileType == FileType::FILE_NOT_FOUND) { string errMsg = "Invalid project path: "; - errMsg += projectPath; + errMsg += toUtf8(projectPath); perror(errMsg.c_str()); exit(2); } else if(projectPathFileType == FileType::REGULAR) { - cerr <<"Expected project path (" << projectPath << ") to be a directory, was a file" << endl; + ferr <<"Expected project path (" << projectPath << ") to be a directory, was a file" << endl; exit(3); } } -void validateFilePath(const char *projectConfPath) +void validateFilePath(const _tinydir_char_t *projectConfPath) { FileType projectConfFileType = getFileType(projectConfPath); if(projectConfFileType == FileType::FILE_NOT_FOUND) { string errMsg = "Invalid project.conf path: "; - errMsg += projectConfPath; + errMsg += toUtf8(projectConfPath); perror(errMsg.c_str()); exit(4); } else if(projectConfFileType == FileType::DIRECTORY) { - cerr << "Expected project path (" << projectConfPath << ") to be a file, was a directory" << endl; + ferr << "Expected project path (" << projectConfPath << ") to be a file, was a directory" << endl; exit(5); } } -const char *sourceFileExtensions[] = { "c", "cc", "cpp", "cxx" }; +const _tinydir_char_t *sourceFileExtensions[] = { TINYDIR_STRING("c"), TINYDIR_STRING("cc"), TINYDIR_STRING("cpp"), TINYDIR_STRING("cxx") }; bool isSourceFile(tinydir_file *file) { if(!file->is_reg) return false; - for(const char *sourceFileExtension : sourceFileExtensions) + for(const _tinydir_char_t *sourceFileExtension : sourceFileExtensions) { if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0) return true; @@ -108,36 +114,36 @@ bool isSourceFile(tinydir_file *file) return false; } -bool isPathSubPathOf(const string &path, const string &subPathOf) +bool isPathSubPathOf(const FileString &path, const FileString &subPathOf) { return _tinydir_strncmp(path.c_str(), subPathOf.c_str(), subPathOf.size()) == 0; } -int buildProject(int argc, const char **argv) +int buildProject(int argc, const _tinydir_char_t **argv) { if(argc > 2) usageBuild(); OptimizationLevel optimizationLevel = OPT_LEV_NONE; - string projectPath; + FileString projectPath; for(int i = 0; i < argc; ++i) { - const char *arg = argv[i]; - if(strcmp(arg, "--debug") == 0) + const _tinydir_char_t *arg = argv[i]; + if(_tinydir_strcmp(arg, TINYDIR_STRING("--debug")) == 0) { if(optimizationLevel != OPT_LEV_NONE) { - fprintf(stderr, "Error: Optimization level defined more than once. First defined as %s then as %s\n", asString(optimizationLevel), "debug"); + ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as debug" << endl; usageBuild(); } optimizationLevel = OPT_LEV_DEBUG; } - else if(strcmp(arg, "--release") == 0) + else if(_tinydir_strcmp(arg, TINYDIR_STRING("--release")) == 0) { if(optimizationLevel != OPT_LEV_NONE) { - fprintf(stderr, "Error: Optimization level defined more than once. First defined as %s then as %s\n", asString(optimizationLevel), "debug"); + ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as release" << endl; usageBuild(); } optimizationLevel = OPT_LEV_RELEASE; @@ -146,7 +152,7 @@ int buildProject(int argc, const char **argv) { if(!projectPath.empty()) { - fprintf(stderr, "Error: Project path was defined more than once. First defined as %s then as %s\n", projectPath.c_str(), arg); + ferr << "Error: Project path was defined more than once. First defined as " << projectPath << " then as " << arg << endl; usageBuild(); } projectPath = arg; @@ -158,35 +164,43 @@ int buildProject(int argc, const char **argv) // TODO: If projectPath is not defined and working directory does not contain project.conf, then search every parent directory until one is found if(projectPath.empty()) - projectPath = "."; + projectPath = TINYDIR_STRING("."); validateDirectoryPath(projectPath.c_str()); if(projectPath.back() != '/') - projectPath += "/"; + projectPath += TINYDIR_STRING("/"); - Result<string> projectRealPathResult = getRealPath(projectPath.c_str()); + Result<FileString> projectRealPathResult = getRealPath(projectPath.c_str()); if(!projectRealPathResult) { - cerr << "Failed to get real path for: '" << projectPath << "': " << projectRealPathResult.getErrMsg() << endl; + ferr << "Failed to get real path for: '" << projectPath.c_str() << "': " << toFileString(projectRealPathResult.getErrMsg()) << endl; exit(40); } projectPath = projectRealPathResult.unwrap(); - string projectConfFilePath = projectPath; - projectConfFilePath += "/project.conf"; + FileString projectConfFilePath = projectPath; + projectConfFilePath += TINYDIR_STRING("/project.conf"); validateFilePath(projectConfFilePath.c_str()); - SibsConfig sibsConfig(projectPath, optimizationLevel); + // TODO: Detect compiler to use at runtime. Should also be configurable + // by passing argument to `sibs build` +#if OS_FAMILY == OS_FAMILY_POSIX + Compiler compiler = Compiler::GCC; +#else + Compiler compiler = Compiler::MSVC; +#endif + + SibsConfig sibsConfig(compiler, projectPath, optimizationLevel); Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig); if(result.isErr()) { - cerr << "Failed to read config: " << result.getErrMsg() << endl; + ferr << "Failed to read config: " << toFileString(result.getErrMsg()) << endl; exit(6); } if(sibsConfig.getPackageName().empty()) { - cerr << "project.conf is missing required field package.name" << endl; + ferr << "project.conf is missing required field package.name" << endl; exit(10); } @@ -216,7 +230,8 @@ int buildProject(int argc, const char **argv) { if (isSourceFile(file)) { - ninja.addSourceFile(file->path + sibsConfig.getProjectPath().size()); + string filePathUtf8 = toUtf8(file->path + sibsConfig.getProjectPath().size()); + ninja.addSourceFile(filePathUtf8.c_str()); } else { @@ -226,66 +241,69 @@ int buildProject(int argc, const char **argv) else { // TODO: If compiling without "test" option, do not add test source dir to ninja. Ninja logic will then not build tests - if(!sibsConfig.getTestPath().empty() && isPathSubPathOf(file->path, sibsConfig.getTestPath())) - ninja.addTestSourceDir(file->path); + if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(file->path, sibsConfig.getTestPath())) + { + string filePathUtf8 = toUtf8(file->path); + ninja.addTestSourceDir(filePathUtf8.c_str()); + } else walkDir(file->path, collectSourceFiles); } }; walkDir(projectPath.c_str(), collectSourceFiles); - string buildPath = projectPath + "/sibs-build/"; + FileString buildPath = projectPath + TINYDIR_STRING("/sibs-build/"); switch(sibsConfig.getOptimizationLevel()) { case OPT_LEV_DEBUG: - buildPath += "debug"; + buildPath += TINYDIR_STRING("debug"); break; case OPT_LEV_RELEASE: - buildPath += "release"; + buildPath += TINYDIR_STRING("release"); break; } Result<bool> buildFileResult = ninja.build(sibsConfig, buildPath.c_str()); if(buildFileResult.isErr()) { - cerr << "Failed to build ninja file: " << buildFileResult.getErrMsg() << endl; + ferr << "Failed to build ninja file: " << toFileString(buildFileResult.getErrMsg()) << endl; exit(7); } return 0; } -void newProjectCreateMainDir(const string &projectPath) +void newProjectCreateMainDir(const FileString &projectPath) { Result<bool> createProjectDirResult = createDirectoryRecursive(projectPath.c_str()); if(createProjectDirResult.isErr()) { - cerr << "Failed to create project main directory: " << createProjectDirResult.getErrMsg() << endl; + ferr << "Failed to create project main directory: " << toFileString(createProjectDirResult.getErrMsg()) << endl; exit(20); } } -void createProjectSubDir(const string &dir) +void createProjectSubDir(const FileString &dir) { Result<bool> createProjectDirResult = createDirectoryRecursive(dir.c_str()); if(createProjectDirResult.isErr()) { - cerr << "Failed to create directory in project: " << createProjectDirResult.getErrMsg() << endl; + ferr << "Failed to create directory in project: " << toFileString(createProjectDirResult.getErrMsg()) << endl; exit(20); } } -void createProjectFile(const string &projectFilePath, const string &fileContent) +void createProjectFile(const FileString &projectFilePath, const string &fileContent) { Result<bool> fileOverwriteResult = fileOverwrite(projectFilePath.c_str(), fileContent.c_str()); if(fileOverwriteResult.isErr()) { - cerr << "Failed to create project file: " << fileOverwriteResult.getErrMsg() << endl; + ferr << "Failed to create project file: " << toFileString(fileOverwriteResult.getErrMsg()) << endl; exit(20); } } -void newProjectCreateConf(const string &projectName, const string &projectType, const string &projectPath) +void newProjectCreateConf(const string &projectName, const string &projectType, const FileString &projectPath) { string projectConfStr = "[package]\n"; projectConfStr += "name = \"" + projectName + "\"\n"; @@ -293,98 +311,102 @@ void newProjectCreateConf(const string &projectName, const string &projectType, projectConfStr += "version = \"0.1.0\"\n\n"; projectConfStr += "[dependencies]\n"; - string projectConfPath = projectPath; - projectConfPath += "/project.conf"; + FileString projectConfPath = projectPath; + projectConfPath += TINYDIR_STRING("/project.conf"); Result<bool> fileOverwriteResult = fileOverwrite(projectConfPath.c_str(), projectConfStr.c_str()); if(fileOverwriteResult.isErr()) { - cerr << "Failed to create project.conf: " << fileOverwriteResult.getErrMsg() << endl; + ferr << "Failed to create project.conf: " << toFileString(fileOverwriteResult.getErrMsg()) << endl; exit(20); } } // This can be replaced with createDirectory and fileOverwrite, but it's not important // so there is no reason to do it (right now) -Result<ExecResult> gitInitProject(const string &projectPath) +Result<ExecResult> gitInitProject(const FileString &projectPath) { - string cmd = "git init '"; + FileString cmd = TINYDIR_STRING("git init \""); cmd += projectPath; - cmd += "'"; + cmd += TINYDIR_STRING("\""); return exec(cmd.c_str()); } -int newProject(int argc, const char **argv) +int newProject(int argc, const _tinydir_char_t **argv) { if(argc != 2) { - cerr << "Expected 'new' command to be followed by two arguments - project name and type of project (--exec, --static or --dynamic)" << endl << endl; + ferr << "Expected 'new' command to be followed by two arguments - project name and type of project (--exec, --static or --dynamic)" << endl << endl; usageNew(); } - Result<string> cwdResult = getCwd(); + Result<FileString> cwdResult = getCwd(); if(cwdResult.isErr()) { - cerr << "Failed to get current working directory: " << cwdResult.getErrMsg() << endl; + ferr << "Failed to get current working directory: " << toFileString(cwdResult.getErrMsg()) << endl; exit(20); } - string projectName = argv[0]; - string projectPath = cwdResult.unwrap(); - projectPath += "/"; - projectPath += projectName; + string projectName = toUtf8(argv[0]); + FileString projectPath = cwdResult.unwrap(); + projectPath += TINYDIR_STRING("/"); + projectPath += toFileString(projectName); bool projectPathExists = getFileType(projectPath.c_str()) != FileType::FILE_NOT_FOUND; if(projectPathExists) { - cerr << "Unable to create a new project at path '" << projectPath << "'. A file or directory already exists in the same location" << endl; + ferr << "Unable to create a new project at path '" << projectPath << "'. A file or directory already exists in the same location" << endl; exit(20); } - const char *projectType = argv[1]; + const _tinydir_char_t *projectType = argv[1]; string projectTypeConf; - if(strcmp(projectType, "--exec") == 0) + if(_tinydir_strcmp(projectType, TINYDIR_STRING("--exec")) == 0) projectTypeConf = "executable"; - else if(strcmp(projectType, "--static") == 0) + else if(_tinydir_strcmp(projectType, TINYDIR_STRING("--static")) == 0) projectTypeConf = "static"; - else if(strcmp(projectType, "--dynamic") == 0) + else if(_tinydir_strcmp(projectType, TINYDIR_STRING("--dynamic")) == 0) projectTypeConf = "dynamic"; else { - cerr << "Expected project type to be either --exec, --static or --dynamic; was: " << projectType << endl << endl; + ferr << "Expected project type to be either --exec, --static or --dynamic; was: " << projectType << endl << endl; usageNew(); } newProjectCreateMainDir(projectPath); newProjectCreateConf(projectName, projectTypeConf, projectPath); - createProjectSubDir(projectPath + "/src"); - createProjectSubDir(projectPath + "/include"); - createProjectFile(projectPath + "/src/main.cpp", "#include <cstdio>\n\nint main()\n{\n return 0;\n}\n"); + createProjectSubDir(projectPath + TINYDIR_STRING("/src")); + createProjectSubDir(projectPath + TINYDIR_STRING("/include")); + createProjectFile(projectPath + TINYDIR_STRING("/src/main.cpp"), "#include <cstdio>\n\nint main()\n{\n return 0;\n}\n"); // We are ignoring git init result on purpose. If it fails, just ignore it; not important gitInitProject(projectPath); return 0; } -int main(int argc, const char **argv) +#if OS_FAMILY == OS_FAMILY_POSIX +int main(int argc, const _tinydir_char_t **argv) +#else +int wmain(int argc, const _tinydir_char_t **argv) +#endif { unordered_map<string, string> param; unordered_set<string> flags; for(int i = 1; i < argc; ++i) { - const char *arg = argv[i]; + const _tinydir_char_t *arg = argv[i]; int subCommandArgCount = argc - i - 1; - const char **subCommandArgPtr = argv + i + 1; - if(strcmp(arg, "build") == 0) + const _tinydir_char_t **subCommandArgPtr = argv + i + 1; + if(_tinydir_strcmp(arg, TINYDIR_STRING("build")) == 0) { return buildProject(subCommandArgCount, subCommandArgPtr); } - else if(strcmp(arg, "new") == 0) + else if(_tinydir_strcmp(arg, TINYDIR_STRING("new")) == 0) { return newProject(subCommandArgCount, subCommandArgPtr); } else { - cerr << "Expected command to be either 'build' or 'new', was: " << arg << endl << endl; + ferr << "Expected command to be either 'build' or 'new', was: " << arg << endl << endl; usage(); } } |