From 5006226e945fc645e6d9b21252c9eee53cc191cc Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 23 Sep 2018 12:22:37 +0200 Subject: Fix various things, add generated zig header files to global include Fix compile_commands.json missing build steps. Fix c includes -> zig includes flags. Fix crash when running sibs new/init without defining lang. Add generated zig header files to global include so they can be used from c/c++. Add zig and zig/c (using zig and c in the same project) examples. --- backend/ninja/Ninja.cpp | 144 ++++++++++++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 54 deletions(-) (limited to 'backend') diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index e71b22a..2c76fd4 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -219,20 +219,14 @@ namespace backend { string filePathStr = filepath ? filepath : ""; if(filepath && !containsSourceFile(filePathStr)) - { sourceFiles.push_back({ language, filePathStr }); - //printf("Adding source file: %s\n", filepath); - } } void Ninja::addTestSourceDir(const char *dir) { string dirStr = dir ? dir : ""; if(dir && !containsTestSourceDir(dirStr)) - { testSourceDirs.emplace_back(dirStr); - //printf("Using test source directory: %s\n", dir); - } } void Ninja::addDependency(const std::string &binaryFile) @@ -440,26 +434,7 @@ namespace backend return result; } - static string convertCIncludeSyntaxToZigInclude(Compiler compiler, const string &cIncludes) - { - switch (compiler) - { - case Compiler::GCC: - { - return replaceAll(cIncludes, "-I", "-isystem "); - } - case Compiler::MSVC: - { - return replaceAll(cIncludes, "/I", "-isystem "); - } - default: - assert(false); - break; - } - return cIncludes; - } - - static vector extractIncludesFromCFlag(Compiler compiler, const ninja::NinjaArg &cflag) + static vector extractIncludesFromCFlag(Compiler compiler, const string &cflag) { vector result; string includeStartStr; @@ -485,42 +460,52 @@ namespace backend while(index != string::npos) { char endChar = ' '; - size_t includeStartIndex = cflag.arg.find(includeStartStr, index); + size_t includeStartIndex = cflag.find(includeStartStr, index); if(includeStartIndex == string::npos) break; else if(includeStartIndex > 0) { - if(cflag.arg[includeStartIndex - 1] == '"' || cflag.arg[includeStartIndex - 1] == '\'') - endChar = cflag.arg[includeStartIndex - 1]; + if(cflag[includeStartIndex - 1] == '"' || cflag[includeStartIndex - 1] == '\'') + endChar = cflag[includeStartIndex - 1]; } includeStartIndex += includeStartStr.length(); - size_t includeEndIndex = cflag.arg.find(endChar, includeStartIndex); + size_t includeEndIndex = cflag.find(endChar, includeStartIndex); index = includeEndIndex; if(includeEndIndex == string::npos) - includeEndIndex = cflag.arg.length(); + includeEndIndex = cflag.length(); - result.push_back(ninja::NinjaArg::createRaw(cflag.arg.substr(includeStartIndex, includeEndIndex - includeStartIndex))); + result.push_back(ninja::NinjaArg::createRaw(cflag.substr(includeStartIndex, includeEndIndex - includeStartIndex))); } return result; } - static vector extractIncludesFromCFlags(Compiler compiler, const vector &cflags) + static vector extractIncludesFromCFlags(Compiler compiler, const vector &cflags) { vector result; for(const ninja::NinjaArg &cflag : cflags) { - vector subCFlags = extractIncludesFromCFlag(compiler, cflag); + vector subCFlags = extractIncludesFromCFlag(compiler, cflag.arg); result.insert(result.end(), subCFlags.begin(), subCFlags.end()); } return result; } + static string convertCIncludeSyntaxToZigInclude(Compiler compiler, const string &cIncludes) + { + vector result = extractIncludesFromCFlag(compiler, cIncludes); + string resultStr; + for(ninja::NinjaArg &include : result) + { + resultStr += "-isystem \"" + include.arg + "\""; + } + return resultStr; + } + static vector convertCFlagsIncludesToZigIncludes(Compiler compiler, const vector &cflags) { - vector result; - result = extractIncludesFromCFlags(compiler, cflags); + vector result = extractIncludesFromCFlags(compiler, cflags); for(ninja::NinjaArg &include : result) { include.arg = "-isystem \"" + include.arg + "\""; @@ -596,14 +581,34 @@ namespace backend return result; } - Result Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) + static int getFilenameLength(const string &filepath) { - if (!sourceFiles.empty()) + for(int i = filepath.size(); i >= 0; --i) { - Result createBuildDirResult = createDirectoryRecursive(savePath); - if (createBuildDirResult.isErr()) - return createBuildDirResult; + char c = filepath[i]; + if(c == '/' || c == '\\') + return filepath.size() - i; } + return filepath.size(); + } + + Result Ninja::build(const SibsConfig &config, const _tinydir_char_t *savePath, LinkerFlagCallbackFunc staticLinkerFlagCallbackFunc, LinkerFlagCallbackFunc dynamicLinkerFlagCallback, GlobalIncludeDirCallbackFunc globalIncludeDirCallback) + { + Result createBuildDirResult = createDirectoryRecursive(savePath); + if (!createBuildDirResult) + return createBuildDirResult; + + FileString generatedHeadersDir = config.getProjectPath() + TINYDIR_STRING("/sibs-build/generated-headers"); + Result createGeneratedHeadersDirResult = createDirectoryRecursive(generatedHeadersDir.c_str()); + if (!createGeneratedHeadersDirResult) + return createGeneratedHeadersDirResult; + + FileString generatedZigHeadersDir = generatedHeadersDir + TINYDIR_STRING("/zig"); + Result createGeneratedZigHeadersDirResult = createDirectory(generatedZigHeadersDir.c_str()); + if (!createGeneratedZigHeadersDirResult) + return createGeneratedZigHeadersDirResult; + + string generatedZigHeaderDirUtf8 = toUtf8(generatedZigHeadersDir); LibraryType libraryType = getNinjaLibraryType(config.getPackageType()); @@ -701,6 +706,7 @@ namespace backend } globalIncDir += dependencyExportIncludeDirs; + globalIncDir += TINYDIR_STRING(" ") + getIncludeOptionFlag(config.getCompiler(), toUtf8(generatedHeadersDir)); ninjaBuildFile.defineGlobalVariable("globalIncDir", globalIncDir); // TODO: Find a better way to convert includes, this could be slow... ninjaBuildFile.defineGlobalVariable("globalIncDirZig", convertCIncludeSyntaxToZigInclude(config.getCompiler(), globalIncDir)); @@ -881,8 +887,10 @@ namespace backend // TODO: Convert sibs defines to const variables in a zig file that other zig files can include (like a config file). // TODO: Remove --library c if project does not depend on c libraries or project only has .zig files + + ninja::NinjaVariable zigHeaderFile("headerFile"); vector zigTestArgs = { - ninja::NinjaArg::createRaw("zig test $in --output $out -isystem ../../ --color on --library c $globalIncDirZig") + ninja::NinjaArg::createRaw("zig test $in --output $out --output-h $headerFile -isystem ../../ --color on --library c $globalIncDirZig") }; // TODO: Find a way to do this more efficiently @@ -891,6 +899,7 @@ namespace backend ninja::NinjaArg::createRaw("zig build-obj"), ninja::NinjaArg::createRaw("$in"), ninja::NinjaArg::createRaw("--output $out"), + ninja::NinjaArg::createRaw("--output-h $headerFile"), ninja::NinjaArg::createRaw("-isystem ../../"), ninja::NinjaArg::createRaw("--color on"), ninja::NinjaArg::createRaw("--library c"), // TODO: Remove this if project does not depend on c libraries or project only has .zig files @@ -934,6 +943,38 @@ namespace backend vector objectNames; objectNames.reserve(sourceFiles.size()); + vector zigBuilds; + // TODO(Urgent): Instead of adding zig builds as dependencies for all c/c++ builds, generate two ninja files; one for zig and one for c/c++. + // Then build run zig ninja file first and then c/c++ ninja file. + // That would be more efficient as you dont need to add every single zig build as dependency for all c/c++ builds... + for(const sibs::SourceFile &sourceFile : sourceFiles) + { + if(sourceFile.language == sibs::Language::ZIG) + { + // TODO: Remove this and use NinjaBuilds to get object names + string objectName = config.getPackageName() + "@exe/" + sourceFile.filepath; + objectName += getObjectFileExtension(config.getCompiler()); + objectNames.emplace_back(objectName); + + // TODO: Optimize this by checking if directory has already been created with a hash map + int filenameLength = getFilenameLength(sourceFile.filepath); + string zigSourceDirRelative = sourceFile.filepath.substr(0, sourceFile.filepath.size() - filenameLength); + FileString zigHeaderFileDir = toFileString(generatedZigHeaderDirUtf8 + '/' + zigSourceDirRelative); + Result createZigHeaderFileDirResult = createDirectoryRecursive(zigHeaderFileDir.c_str()); + if(!createZigHeaderFileDirResult) + return createZigHeaderFileDirResult; + + string headerName = sourceFile.filepath.substr(sourceFile.filepath.size() - filenameLength, filenameLength - 4) + ".h"; + ninja::NinjaArgValue zigHeaderFileValue = { zigHeaderFile, '"' + toUtf8(zigHeaderFileDir) + '/' + headerName + '"' }; + ninja::NinjaBuild *ninjaBuild = nullptr; + if(zigTest) + ninjaBuild = testZigRule->build("../../" + sourceFile.filepath, objectName, { zigHeaderFileValue }); + else + ninjaBuild = compileZigRule->build("../../" + sourceFile.filepath, objectName, { zigHeaderFileValue }); + zigBuilds.push_back(ninjaBuild); + } + } + for(const sibs::SourceFile &sourceFile : sourceFiles) { string objectName; @@ -943,7 +984,7 @@ namespace backend { objectName += config.getPackageName() + "@exe/" + sourceFile.filepath; objectName += getObjectFileExtension(config.getCompiler()); - ninjaBuildFile.build(compileCRule, "../../" + sourceFile.filepath, objectName, {}); + compileCRule->build("../../" + sourceFile.filepath, objectName, {}, zigBuilds); usesCFiles = true; break; } @@ -951,18 +992,13 @@ namespace backend { objectName += config.getPackageName() + "@exe/" + sourceFile.filepath; objectName += getObjectFileExtension(config.getCompiler()); - ninjaBuildFile.build(compileCppRule, "../../" + sourceFile.filepath, objectName, {}); + compileCppRule->build("../../" + sourceFile.filepath, objectName, {}, zigBuilds); usesCppFiles = true; break; } case sibs::Language::ZIG: { - objectName += "zig-cache/" + sourceFile.filepath; - objectName += getObjectFileExtension(config.getCompiler()); - if(zigTest) - ninjaBuildFile.build(testZigRule, "../../" + sourceFile.filepath, objectName, {}); - else - ninjaBuildFile.build(compileZigRule, "../../" + sourceFile.filepath, objectName, {}); + // Already built above break; } default: @@ -1041,7 +1077,7 @@ namespace backend buildExeArgs.push_back(ninja::NinjaArg::createRaw(allLinkerFlags)); ninja::NinjaRule *buildExeRule = ninjaBuildFile.createRule("build_exec", buildExeArgs); - ninjaBuildFile.build(buildExeRule, join(objectNames, " "), config.getPackageName(), {}); + buildExeRule->build(join(objectNames, " "), config.getPackageName(), {}); projectGeneratedBinary += config.getPackageName(); #if OS_FAMILY == OS_FAMILY_WINDOWS @@ -1079,7 +1115,7 @@ namespace backend } ninja::NinjaRule *buildStaticRule = ninjaBuildFile.createRule("build_static", buildStaticArgs); - ninjaBuildFile.build(buildStaticRule, join(objectNames, " "), generatedFile, {}); + buildStaticRule->build(join(objectNames, " "), generatedFile, {}); projectGeneratedBinary += generatedFile; projectGeneratedBinary += "\""; @@ -1149,7 +1185,7 @@ namespace backend buildDynamicArgs.push_back(ninja::NinjaArg::createRaw(allLinkerFlags)); ninja::NinjaRule *buildDynamicRule = ninjaBuildFile.createRule("build_dynamic", buildDynamicArgs); - ninjaBuildFile.build(buildDynamicRule, join(objectNames, " "), generatedFile, {}); + buildDynamicRule->build(join(objectNames, " "), generatedFile, {}); projectGeneratedBinary += generatedFile; projectGeneratedBinary += "\""; @@ -1348,7 +1384,7 @@ namespace backend { FileString command = TINYDIR_STRING("ninja -C \""); command += buildFilePath; - command += TINYDIR_STRING("\" -t compdb c_COMPILER cpp_COMPILER BUILD_EXEC BUILD_STATIC BUILD_DYNAMIC > \""); + command += TINYDIR_STRING("\" -t compdb compile_c compile_cpp compile_zig > \""); command += saveDir; command += TINYDIR_STRING("/compile_commands.json\""); Result execResult = exec(command.c_str(), false); -- cgit v1.2.3