diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index b6d97d17e..d38cf7ee7 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -121,7 +121,8 @@ Available logical expressions are: target_link_libraries(myapp myapp_c myapp_cxx) The ``Makefile`` and ``Ninja`` based generators can also use this - expression to specify compile-language specific compile definitions: + expression to specify compile-language specific compile definitions + and include directories: .. code-block:: cmake @@ -129,6 +130,9 @@ Available logical expressions are: target_compile_definitions(myapp PRIVATE $<$:COMPILING_CXX> ) + target_include_directories(myapp + PRIVATE $<$:/opt/foo/cxx_headers> + ) Informational Expressions ========================= diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 3ec8595a9..756d93206 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -851,7 +851,8 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode } else if (genName.find("Xcode") != std::string::npos) { - if (dagChecker && dagChecker->EvaluatingCompileDefinitions()) + if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() + || dagChecker->EvaluatingIncludeDirectories())) { reportError(context, content->GetOriginalExpression(), "$ may only be used with COMPILE_OPTIONS " diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 44c9e9a59..b7b2effc4 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -960,9 +960,10 @@ cmGeneratorTarget::GetCreateRuleVariable(std::string const& lang, //---------------------------------------------------------------------------- std::vector -cmGeneratorTarget::GetIncludeDirectories(const std::string& config) const +cmGeneratorTarget::GetIncludeDirectories(const std::string& config, + const std::string& lang) const { - return this->Target->GetIncludeDirectories(config); + return this->Target->GetIncludeDirectories(config, lang); } //---------------------------------------------------------------------------- diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 2083b8858..c329cf55e 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -85,7 +85,7 @@ public: /** Get the include directories for this target. */ std::vector GetIncludeDirectories( - const std::string& config) const; + const std::string& config, const std::string& lang) const; bool IsSystemIncludeDirectory(const std::string& dir, const std::string& config) const; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 735dfa96b..37cc2c662 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1600,7 +1600,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector& dirs, // Get the target-specific include directories. std::vector includes; - includes = target->GetIncludeDirectories(config); + includes = target->GetIncludeDirectories(config, lang); // Support putting all the in-project include directories first if // it is requested by the project. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 9ecb02948..50491af28 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -2114,6 +2114,32 @@ void cmLocalUnixMakefileGenerator3 cmakefileStream << " )\n"; } + + // Target-specific include directories: + cmakefileStream + << "\n" + << "# The include file search paths:\n"; + cmakefileStream + << "set(CMAKE_" << l->first << "_TARGET_INCLUDE_PATH\n"; + std::vector includes; + + cmGeneratorTarget* gt = this->GetGlobalGenerator() + ->GetGeneratorTarget(&target); + + const std::string& config = + this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + this->GetIncludeDirectories(includes, gt, + l->first, config); + for(std::vector::iterator i = includes.begin(); + i != includes.end(); ++i) + { + cmakefileStream + << " \"" + << this->Convert(*i, cmLocalGenerator::HOME_OUTPUT) + << "\"\n"; + } + cmakefileStream + << " )\n"; } // Store include transform rule properties. Write the directory diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 57c49f165..c7a7110a1 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1056,40 +1056,6 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" << mdir << "\")\n"; } - // Target-specific include directories: - *this->InfoFileStream - << "\n" - << "# The include file search paths:\n"; - *this->InfoFileStream - << "set(CMAKE_C_TARGET_INCLUDE_PATH\n"; - std::vector includes; - - const std::string& config = - this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); - this->LocalGenerator->GetIncludeDirectories(includes, - this->GeneratorTarget, - "C", config); - for(std::vector::iterator i = includes.begin(); - i != includes.end(); ++i) - { - *this->InfoFileStream - << " \"" - << this->LocalGenerator->Convert(*i, - cmLocalGenerator::HOME_OUTPUT) - << "\"\n"; - } - *this->InfoFileStream - << " )\n"; - *this->InfoFileStream - << "set(CMAKE_CXX_TARGET_INCLUDE_PATH " - << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; - *this->InfoFileStream - << "set(CMAKE_Fortran_TARGET_INCLUDE_PATH " - << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; - *this->InfoFileStream - << "set(CMAKE_ASM_TARGET_INCLUDE_PATH " - << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; - // and now write the rule to use it std::vector depends; std::vector commands; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 87dcc99a4..7a6ad8b4f 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1979,7 +1979,8 @@ static void processIncludeDirectories(cmTarget const* tgt, std::vector &includes, UNORDERED_SET &uniqueIncludes, cmGeneratorExpressionDAGChecker *dagChecker, - const std::string& config, bool debugIncludes) + const std::string& config, bool debugIncludes, + const std::string& language) { cmMakefile *mf = tgt->GetMakefile(); @@ -1995,7 +1996,7 @@ static void processIncludeDirectories(cmTarget const* tgt, config, false, tgt, - dagChecker), + dagChecker, language), entryIncludes); std::string usedIncludes; @@ -2106,7 +2107,8 @@ static void processIncludeDirectories(cmTarget const* tgt, //---------------------------------------------------------------------------- std::vector -cmTarget::GetIncludeDirectories(const std::string& config) const +cmTarget::GetIncludeDirectories(const std::string& config, + const std::string& language) const { std::vector includes; UNORDERED_SET uniqueIncludes; @@ -2139,7 +2141,8 @@ cmTarget::GetIncludeDirectories(const std::string& config) const uniqueIncludes, &dagChecker, config, - debugIncludes); + debugIncludes, + language); std::vector linkInterfaceIncludeDirectoriesEntries; @@ -2179,7 +2182,8 @@ cmTarget::GetIncludeDirectories(const std::string& config) const uniqueIncludes, &dagChecker, config, - debugIncludes); + debugIncludes, + language); deleteAndClear(linkInterfaceIncludeDirectoriesEntries); diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 0356c1ec1..5170b3190 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -568,7 +568,8 @@ public: bool contentOnly) const; std::vector GetIncludeDirectories( - const std::string& config) const; + const std::string& config, + const std::string& language) const; void InsertInclude(const cmValueWithOrigin &entry, bool before = false); void InsertCompileOption(const cmValueWithOrigin &entry, diff --git a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt index 661bbaab6..d57556aad 100644 --- a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt +++ b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt @@ -42,6 +42,20 @@ add_executable(consumer "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp" ) +if (CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja") + target_sources(consumer PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c" + ) + target_include_directories(consumer + PRIVATE + $<$:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/c_only> + ) + target_compile_definitions(consumer + PRIVATE -DTEST_LANG_DEFINES + ) +endif() + target_include_directories(consumer PRIVATE $ diff --git a/Tests/CMakeCommands/target_include_directories/c_only/c_only.h b/Tests/CMakeCommands/target_include_directories/c_only/c_only.h new file mode 100644 index 000000000..29f68ee33 --- /dev/null +++ b/Tests/CMakeCommands/target_include_directories/c_only/c_only.h @@ -0,0 +1,2 @@ + +#define C_ONLY_DEFINE diff --git a/Tests/CMakeCommands/target_include_directories/consumer.c b/Tests/CMakeCommands/target_include_directories/consumer.c new file mode 100644 index 000000000..8821f5bc7 --- /dev/null +++ b/Tests/CMakeCommands/target_include_directories/consumer.c @@ -0,0 +1,10 @@ + +#ifdef TEST_LANG_DEFINES + #include "c_only.h" + + #ifndef C_ONLY_DEFINE + #error Expected C_ONLY_DEFINE + #endif +#endif + +int consumer_c() { return 0; } diff --git a/Tests/CMakeCommands/target_include_directories/consumer.cpp b/Tests/CMakeCommands/target_include_directories/consumer.cpp index 7e3443ec3..649510ce0 100644 --- a/Tests/CMakeCommands/target_include_directories/consumer.cpp +++ b/Tests/CMakeCommands/target_include_directories/consumer.cpp @@ -4,6 +4,9 @@ #include "interfaceinclude.h" #include "relative_dir.h" #include "consumer.h" +#ifdef TEST_LANG_DEFINES + #include "cxx_only.h" +#endif #ifdef PRIVATEINCLUDE_DEFINE #error Unexpected PRIVATEINCLUDE_DEFINE @@ -29,4 +32,10 @@ #error Expected CONSUMER_DEFINE #endif +#ifdef TEST_LANG_DEFINES + #ifndef CXX_ONLY_DEFINE + #error Expected CXX_ONLY_DEFINE + #endif +#endif + int main() { return 0; } diff --git a/Tests/CMakeCommands/target_include_directories/cxx_only/cxx_only.h b/Tests/CMakeCommands/target_include_directories/cxx_only/cxx_only.h new file mode 100644 index 000000000..67289a4fb --- /dev/null +++ b/Tests/CMakeCommands/target_include_directories/cxx_only/cxx_only.h @@ -0,0 +1,2 @@ + +#define CXX_ONLY_DEFINE diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt new file mode 100644 index 000000000..ec15068e9 --- /dev/null +++ b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt @@ -0,0 +1,8 @@ +CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\): + Error evaluating generator expression: + + \$ + + \$ may not be used with Visual Studio generators. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt new file mode 100644 index 000000000..fdf92b28f --- /dev/null +++ b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-Xcode.txt @@ -0,0 +1,9 @@ +CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\): + Error evaluating generator expression: + + \$ + + \$ may only be used with COMPILE_OPTIONS with the + Xcode generator. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake new file mode 100644 index 000000000..31771f64d --- /dev/null +++ b/Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories.cmake @@ -0,0 +1,5 @@ + +enable_language(CXX) + +add_executable(main main.cpp) +target_include_directories(main PRIVATE $<$:anydir>) diff --git a/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake b/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake index 8a32aef49..5e0a5f512 100644 --- a/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake +++ b/Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake @@ -11,3 +11,10 @@ elseif (RunCMake_GENERATOR MATCHES "Visual Studio") set(RunCMake-stderr-file CompileDefinitions-stderr-VS.txt) run_cmake(CompileDefinitions) endif() +if (RunCMake_GENERATOR STREQUAL "Xcode") + set(RunCMake-stderr-file IncludeDirectories-stderr-Xcode.txt) + run_cmake(IncludeDirectories) +elseif (RunCMake_GENERATOR MATCHES "Visual Studio") + set(RunCMake-stderr-file IncludeDirectories-stderr-VS.txt) + run_cmake(IncludeDirectories) +endif()