diff --git a/src/CmakeRegen.cpp b/src/CmakeRegen.cpp index 619e61c..199d6d6 100644 --- a/src/CmakeRegen.cpp +++ b/src/CmakeRegen.cpp @@ -103,7 +103,7 @@ void RegenerateCmakeFilesForComponent(const Configuration& config, Component *co RegenerateCmakeHeader(o, config); if (comp->root == ".") { - // Do this for the user, so that you don't get a warning on either + // Do this for the user, so that you don't get a warning on either // not doing this, or doing this in the addon file. o << "cmake_minimum_required(VERSION " << config.cmakeVersion << ")\n"; } @@ -186,30 +186,31 @@ void RegenerateCmakeAddSubdirectory(std::ostream& o, for (auto subdir : subdirs) { o << "add_subdirectory(" << subdir << ")\n"; } - + } void RegenerateCmakeAddTarget(std::ostream& o, const Configuration& config, - const Component& comp, + Component& comp, const std::list& files, bool isHeaderOnly) { o << comp.type << "(${PROJECT_NAME}"; if (isHeaderOnly) { - o << " INTERFACE\n"; - } else { - if (config.addLibraryAliases.count(comp.type) == 1) { - o << " STATIC\n"; - } else { - o << "\n"; - } + comp.additionalTargetParameters.insert("INTERFACE"); + } + if (!comp.additionalTargetParameters.empty()) { + for (auto &s : comp.additionalTargetParameters) { + o << " " << s; + } + } + o << "\n"; + if (!isHeaderOnly) { for (auto &f : files) { o << " " << f << "\n"; } } - o << comp.additionalTargetParameters; o << ")\n\n"; } diff --git a/src/CmakeRegen.h b/src/CmakeRegen.h index 3311a12..61ee7d5 100644 --- a/src/CmakeRegen.h +++ b/src/CmakeRegen.h @@ -27,7 +27,7 @@ struct Configuration; void RegenerateCmakeFilesForComponent(const Configuration& config, Component *comp, - bool dryRun, + bool dryRun, bool writeToStdout); void MakeCmakeComment(std::string& cmakeComment, @@ -39,7 +39,7 @@ void RegenerateCmakeAddSubdirectory(std::ostream& o, const Component& comp); void RegenerateCmakeAddTarget(std::ostream& o, const Configuration& config, - const Component& comp, + Component& comp, const std::list& files, bool isHeaderOnly); void RegenerateCmakeHeader(std::ostream& o, const Configuration& config); diff --git a/src/Component.h b/src/Component.h index 96072a3..029b9ae 100644 --- a/src/Component.h +++ b/src/Component.h @@ -87,7 +87,7 @@ struct Component { bool hasAddonCmake; std::string type; size_t index, lowlink; - std::string additionalTargetParameters; + std::set additionalTargetParameters; std::string additionalCmakeDeclarations; bool onStack; }; @@ -106,5 +106,3 @@ void CreateIncludeLookupTable(std::unordered_map& files, std::map> &collisions); #endif - - diff --git a/src/Input.cpp b/src/Input.cpp index 571570a..2072e16 100644 --- a/src/Input.cpp +++ b/src/Input.cpp @@ -208,7 +208,7 @@ static bool IsItemBlacklisted(const Configuration& config, const filesystem::pat if (pathS.compare(2, s.size(), s) == 0) { return true; } - if (s == fileName) + if (s == fileName) return true; } return false; @@ -250,58 +250,60 @@ static void ReadCmakelist(const Configuration& config, std::unordered_map 0 && line[0] == '#') { + if ((line.size() > 0 && line[0] == '#') || line.empty()) { continue; } - int newParenLevel = parenLevel + std::count(line.begin(), line.end(), '(') + int newParentLevel = parentLevel + std::count(line.begin(), line.end(), '(') - std::count(line.begin(), line.end(), ')'); if (strstr(line.c_str(), "project(") == line.c_str()) { size_t end = line.find(')'); if (end != line.npos) { comp.name = line.substr(8, end - 8); } - } - else if (TryGetComponentType(comp, config.addLibraryAliases, line)) { + } else if (TryGetComponentType(comp, config.addLibraryAliases, line)) { inTargetDefinition = true; } else if (TryGetComponentType(comp, config.addExecutableAliases, line)) { inTargetDefinition = true; - } else if (inTargetDefinition) { - const size_t endOfLine = (newParenLevel == 0) ? line.find_last_of(')') - : line.length(); - if (endOfLine > 0) { - const std::string targetLine(line.substr(0, endOfLine)); - if (!strstr(targetLine.c_str(), "${IMPLEMENTATION_SOURCES}") && - !strstr(targetLine.c_str(), "${IMPLEMENTATION_HEADERS}") && - !IsCode(filesystem::path(targetLine).extension().generic_string())) { - comp.additionalTargetParameters.append(targetLine + '\n'); - } - } - if (newParenLevel == 0) { - inTargetDefinition = false; - } } else if (config.reuseCustomSections) { if (IsAutomaticlyGeneratedSection(line)) { inAutoSection = true; } else { - if (!inAutoSection && !line.empty()) { + if (!inAutoSection && !line.empty() && !inTargetDefinition) { comp.additionalCmakeDeclarations.append(line + '\n'); } } - if (inAutoSection && newParenLevel == 0) { + if (inAutoSection && newParentLevel == 0) { inAutoSection = false; } } - parenLevel = newParenLevel; + if (inTargetDefinition) { + const size_t endOfLine = (newParentLevel == 0) ? line.find_last_of(')') + : line.length(); + if (endOfLine > 0) { + const std::string targetLine(line.substr(0, endOfLine)); + static const std::unordered_set cmakeTargetParameters = { "ALIAS", "EXCLUDE_FROM_ALL", "GLOBAL", "IMPORTED", "INTERFACE", "MACOSX_BUNDLE", "MODULE", "OBJECT", "STATIC", "SHARED", "UNKNOWN", "WIN32" }; + for (auto& cmakeTargetParameter : cmakeTargetParameters) { + int pos = targetLine.find(cmakeTargetParameter.c_str()); + if (pos != std::string::npos) { + comp.additionalTargetParameters.insert(cmakeTargetParameter); + } + } + } + if (newParentLevel == 0) { + inTargetDefinition = false; + } + } + parentLevel = newParentLevel; } while (in.good()); - assert(parenLevel == 0 || (printf("final level of parentheses=%d\n", parenLevel), 0)); + assert(parentLevel == 0 || (printf("final level of parentheses=%d\n", parentLevel), 0)); } void LoadFileList(const Configuration& config, @@ -327,7 +329,7 @@ void LoadFileList(const Configuration& config, it.disable_recursion_pending(); #endif continue; - } + } if (inferredComponents) AddComponentDefinition(components, parent); @@ -352,5 +354,3 @@ void ForgetEmptyComponents(std::unordered_map &compone ++it; } } - - diff --git a/test/CmakeRegenTest.cpp b/test/CmakeRegenTest.cpp index 9eca752..75dcbf7 100644 --- a/test/CmakeRegenTest.cpp +++ b/test/CmakeRegenTest.cpp @@ -299,7 +299,7 @@ TEST(RegenerateCmakeTargetLinkLibraries_Interface) { TEST(RegenerateCmakeAddTarget_Interface) { Component comp("./MyComponent/"); comp.type = "add_library"; - comp.additionalTargetParameters = " EXCLUDE_FROM_ALL\n"; + comp.additionalTargetParameters = { "EXCLUDE_FROM_ALL" }; Configuration config; @@ -312,8 +312,7 @@ TEST(RegenerateCmakeAddTarget_Interface) { }; const std::string expectedOutput( - "add_library(${PROJECT_NAME} INTERFACE\n" - " EXCLUDE_FROM_ALL\n" + "add_library(${PROJECT_NAME} EXCLUDE_FROM_ALL INTERFACE\n" ")\n" "\n"); @@ -326,7 +325,7 @@ TEST(RegenerateCmakeAddTarget_Interface) { TEST(RegenerateCmakeAddTarget_Library) { Component comp("./MyComponent/"); comp.type = "add_library"; - comp.additionalTargetParameters = " EXCLUDE_FROM_ALL\n"; + comp.additionalTargetParameters = { "EXCLUDE_FROM_ALL" }; Configuration config; @@ -339,11 +338,10 @@ TEST(RegenerateCmakeAddTarget_Library) { }; const std::string expectedOutput( - "add_library(${PROJECT_NAME} STATIC\n" + "add_library(${PROJECT_NAME} EXCLUDE_FROM_ALL\n" " Analysis.cpp\n" " Analysis.h\n" " main.cpp\n" - " EXCLUDE_FROM_ALL\n" ")\n" "\n"); @@ -356,7 +354,7 @@ TEST(RegenerateCmakeAddTarget_Library) { TEST(RegenerateCmakeAddTarget_LibraryAlias) { Component comp("./MyComponent/"); comp.type = "add_library_alias"; - comp.additionalTargetParameters = " EXCLUDE_FROM_ALL\n"; + comp.additionalTargetParameters = { "EXCLUDE_FROM_ALL" }; Configuration config; config.addLibraryAliases.insert("add_library_alias"); @@ -370,11 +368,10 @@ TEST(RegenerateCmakeAddTarget_LibraryAlias) { }; const std::string expectedOutput( - "add_library_alias(${PROJECT_NAME} STATIC\n" + "add_library_alias(${PROJECT_NAME} EXCLUDE_FROM_ALL\n" " Analysis.cpp\n" " Analysis.h\n" " main.cpp\n" - " EXCLUDE_FROM_ALL\n" ")\n" "\n"); @@ -387,7 +384,7 @@ TEST(RegenerateCmakeAddTarget_LibraryAlias) { TEST(RegenerateCmakeAddTarget_Executable) { Component comp("./MyComponent/"); comp.type = "add_executable"; - comp.additionalTargetParameters = " EXCLUDE_FROM_ALL\n"; + comp.additionalTargetParameters = { "EXCLUDE_FROM_ALL" }; Configuration config; @@ -400,11 +397,10 @@ TEST(RegenerateCmakeAddTarget_Executable) { }; const std::string expectedOutput( - "add_executable(${PROJECT_NAME}\n" + "add_executable(${PROJECT_NAME} EXCLUDE_FROM_ALL\n" " Analysis.cpp\n" " Analysis.h\n" " main.cpp\n" - " EXCLUDE_FROM_ALL\n" ")\n" "\n"); diff --git a/test/InputTest.cpp b/test/InputTest.cpp index a9fbbdb..270669e 100644 --- a/test/InputTest.cpp +++ b/test/InputTest.cpp @@ -74,3 +74,29 @@ TEST(Input_Aliases) } } } + +TEST(Input_AdditionalTargetParameters) +{ + TemporaryWorkingDirectory workDir(name); + + { + streams::ofstream out(workDir() / "CMakeLists.txt"); + out << "project(TestProject)\n" + << "add_library(${PROJECT_NAME} SHARED EXCLUDE_FROM_ALL somesourcefile.cpp)\n"; + } + + Configuration config; + + std::unordered_map components; + std::unordered_map files; + + LoadFileList(config, components, files, workDir(), true, false); + + ASSERT(components.size() == 1); + + for (auto& pair : components) { + const Component& comp = *pair.second; + ASSERT(comp.additionalTargetParameters.size() == 2); + ASSERT(*comp.additionalTargetParameters.begin() == "EXCLUDE_FROM_ALL"); + } +}