diff options
17 files changed, 179 insertions, 56 deletions
diff --git a/Help/command/get_filename_component.rst b/Help/command/get_filename_component.rst index 60488da..82f9120 100644 --- a/Help/command/get_filename_component.rst +++ b/Help/command/get_filename_component.rst @@ -3,6 +3,8 @@ get_filename_component Get a specific component of a full filename. +------------------------------------------------------------------------------ + :: get_filename_component(<VAR> <FileName> <COMP> [CACHE]) @@ -15,8 +17,6 @@ Set ``<VAR>`` to a component of ``<FileName>``, where ``<COMP>`` is one of: NAME = File name without directory EXT = File name longest extension (.b.c from d/a.b.c) NAME_WE = File name without directory or longest extension - ABSOLUTE = Full path to file - REALPATH = Full path to existing file with symlinks resolved PATH = Legacy alias for DIRECTORY (use for CMake <= 2.8.11) Paths are returned with forward slashes and have no trailing slahes. @@ -24,14 +24,41 @@ The longest file extension is always considered. If the optional ``CACHE`` argument is specified, the result variable is added to the cache. +------------------------------------------------------------------------------ + +:: + + get_filename_component(<VAR> <FileName> + <COMP> [BASE_DIR <BASE_DIR>] + [CACHE]) + +Set ``<VAR>`` to the absolute path of ``<FileName>``, where ``<COMP>`` is one +of: + +:: + + ABSOLUTE = Full path to file + REALPATH = Full path to existing file with symlinks resolved + +If the provided ``<FileName>`` is a relative path, it is evaluated relative +to the given base directory ``<BASE_DIR>``. If no base directory is +provided, the default base directory will be +:variable:`CMAKE_CURRENT_SOURCE_DIR`. + +Paths are returned with forward slashes and have no trailing slahes. If the +optional ``CACHE`` argument is specified, the result variable is added to the +cache. + +------------------------------------------------------------------------------ + :: - get_filename_component(<VAR> FileName + get_filename_component(<VAR> <FileName> PROGRAM [PROGRAM_ARGS <ARG_VAR>] [CACHE]) -The program in ``FileName`` will be found in the system search path or +The program in ``<FileName>`` will be found in the system search path or left as a full path. If ``PROGRAM_ARGS`` is present with ``PROGRAM``, then -any command-line arguments present in the ``FileName`` string are split +any command-line arguments present in the ``<FileName>`` string are split from the program name and stored in ``<ARG_VAR>``. This is used to separate a program name from its arguments in a command line string. diff --git a/Help/release/dev/get-filename-component-base-dir.rst b/Help/release/dev/get-filename-component-base-dir.rst new file mode 100644 index 0000000..c0df759 --- /dev/null +++ b/Help/release/dev/get-filename-component-base-dir.rst @@ -0,0 +1,6 @@ +get-filename-component-base-dir +------------------------------- + +* The :command:`get_filename_component` command learned a new ``BASE_DIR`` + subcommand. This is used to specify a base directory when calculating an + absolute path from a relative path. diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake index 492c3ea..9bd1d67 100644 --- a/Modules/CMakeDetermineCCompiler.cmake +++ b/Modules/CMakeDetermineCCompiler.cmake @@ -96,6 +96,7 @@ if(NOT CMAKE_C_COMPILER_ID_RUN) # Try to identify the compiler. set(CMAKE_C_COMPILER_ID) + set(CMAKE_C_PLATFORM_ID) file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in CMAKE_C_COMPILER_ID_PLATFORM_CONTENT) @@ -117,12 +118,12 @@ if(NOT CMAKE_C_COMPILER_ID_RUN) CMAKE_DETERMINE_COMPILER_ID(C CFLAGS CMakeCCompilerId.c) # Set old compiler and platform id variables. - if(CMAKE_C_COMPILER_ID MATCHES "GNU") + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") set(CMAKE_COMPILER_IS_GNUCC 1) endif() - if("${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW") + if(CMAKE_C_PLATFORM_ID MATCHES "MinGW") set(CMAKE_COMPILER_IS_MINGW 1) - elseif("${CMAKE_C_PLATFORM_ID}" MATCHES "Cygwin") + elseif(CMAKE_C_PLATFORM_ID MATCHES "Cygwin") set(CMAKE_COMPILER_IS_CYGWIN 1) endif() endif() diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake index 2032015..f25a2db 100644 --- a/Modules/CMakeDetermineCXXCompiler.cmake +++ b/Modules/CMakeDetermineCXXCompiler.cmake @@ -91,6 +91,7 @@ if(NOT CMAKE_CXX_COMPILER_ID_RUN) # Try to identify the compiler. set(CMAKE_CXX_COMPILER_ID) + set(CMAKE_CXX_PLATFORM_ID) file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in CMAKE_CXX_COMPILER_ID_PLATFORM_CONTENT) @@ -112,12 +113,12 @@ if(NOT CMAKE_CXX_COMPILER_ID_RUN) CMAKE_DETERMINE_COMPILER_ID(CXX CXXFLAGS CMakeCXXCompilerId.cpp) # Set old compiler and platform id variables. - if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_COMPILER_IS_GNUCXX 1) endif() - if("${CMAKE_CXX_PLATFORM_ID}" MATCHES "MinGW") + if(CMAKE_CXX_PLATFORM_ID MATCHES "MinGW") set(CMAKE_COMPILER_IS_MINGW 1) - elseif("${CMAKE_CXX_PLATFORM_ID}" MATCHES "Cygwin") + elseif(CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin") set(CMAKE_COMPILER_IS_CYGWIN 1) endif() endif() diff --git a/Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake b/Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake index 064e650..3bfb876 100644 --- a/Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake +++ b/Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake @@ -101,6 +101,8 @@ if (NOT CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS) _DETERMINE_GCC_SYSTEM_INCLUDE_DIRS(c _dirs _defines) set(CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS "${_dirs}" CACHE INTERNAL "C compiler system include directories") set(CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS "${_defines}" CACHE INTERNAL "C compiler system defined macros") + elseif ("${CMAKE_C_COMPILER_ID}" MATCHES MSVC) + set(CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS "$ENV{INCLUDE}" CACHE INTERNAL "C compiler system include directories") endif () endif () @@ -110,6 +112,8 @@ if (NOT CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS) _DETERMINE_GCC_SYSTEM_INCLUDE_DIRS(c++ _dirs _defines) set(CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS "${_dirs}" CACHE INTERNAL "CXX compiler system include directories") set(CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS "${_defines}" CACHE INTERNAL "CXX compiler system defined macros") + elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES MSVC) + set(CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS "$ENV{INCLUDE}" CACHE INTERNAL "CXX compiler system include directories") endif () endif () diff --git a/Modules/Platform/HP-UX.cmake b/Modules/Platform/HP-UX.cmake index 581301b..88932ad 100644 --- a/Modules/Platform/HP-UX.cmake +++ b/Modules/Platform/HP-UX.cmake @@ -1,9 +1,11 @@ set(CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH /usr/lib) -set(CMAKE_SHARED_LIBRARY_SUFFIX ".sl") # .so +if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "ia64") + set(CMAKE_SHARED_LIBRARY_SUFFIX ".sl") # .so + set(CMAKE_FIND_LIBRARY_SUFFIXES ".sl" ".so" ".a") + set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".so") +endif() set(CMAKE_DL_LIBS "dld") -set(CMAKE_FIND_LIBRARY_SUFFIXES ".sl" ".so" ".a") -set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".so") # The HP linker needs to find transitive shared library dependencies # in the -L path. Therefore the runtime path must be added to the diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 54bbbbb..e2de794 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 3) -set(CMake_VERSION_PATCH 20150820) +set(CMake_VERSION_PATCH 20150821) #set(CMake_VERSION_RC 1) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 299c112..530acfe 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -270,48 +270,71 @@ const char *cmGeneratorTarget::GetProperty(const std::string& prop) const std::string cmGeneratorTarget::GetOutputName(const std::string& config, bool implib) const { - std::vector<std::string> props; - std::string type = this->Target->GetOutputTargetType(implib); - std::string configUpper = cmSystemTools::UpperCase(config); - if(!type.empty() && !configUpper.empty()) - { - // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG> - props.push_back(type + "_OUTPUT_NAME_" + configUpper); - } - if(!type.empty()) + // Lookup/compute/cache the output name for this configuration. + OutputNameKey key(config, implib); + cmGeneratorTarget::OutputNameMapType::iterator i = + this->OutputNameMap.find(key); + if(i == this->OutputNameMap.end()) { - // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME - props.push_back(type + "_OUTPUT_NAME"); - } - if(!configUpper.empty()) - { - // OUTPUT_NAME_<CONFIG> - props.push_back("OUTPUT_NAME_" + configUpper); - // <CONFIG>_OUTPUT_NAME - props.push_back(configUpper + "_OUTPUT_NAME"); - } - // OUTPUT_NAME - props.push_back("OUTPUT_NAME"); + // Add empty name in map to detect potential recursion. + OutputNameMapType::value_type entry(key, ""); + i = this->OutputNameMap.insert(entry).first; - std::string outName; - for(std::vector<std::string>::const_iterator i = props.begin(); - i != props.end(); ++i) - { - if (const char* outNameProp = this->Target->GetProperty(*i)) + // Compute output name. + std::vector<std::string> props; + std::string type = this->Target->GetOutputTargetType(implib); + std::string configUpper = cmSystemTools::UpperCase(config); + if(!type.empty() && !configUpper.empty()) { - outName = outNameProp; - break; + // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG> + props.push_back(type + "_OUTPUT_NAME_" + configUpper); + } + if(!type.empty()) + { + // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME + props.push_back(type + "_OUTPUT_NAME"); + } + if(!configUpper.empty()) + { + // OUTPUT_NAME_<CONFIG> + props.push_back("OUTPUT_NAME_" + configUpper); + // <CONFIG>_OUTPUT_NAME + props.push_back(configUpper + "_OUTPUT_NAME"); + } + // OUTPUT_NAME + props.push_back("OUTPUT_NAME"); + + std::string outName; + for(std::vector<std::string>::const_iterator it = props.begin(); + it != props.end(); ++it) + { + if (const char* outNameProp = this->Target->GetProperty(*it)) + { + outName = outNameProp; + break; + } } - } - if (outName.empty()) + if(outName.empty()) + { + outName = this->GetName(); + } + + // Now evaluate genex and update the previously-prepared map entry. + cmGeneratorExpression ge; + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName); + i->second = cge->Evaluate(this->Makefile, config); + } + else if(i->second.empty()) { - outName = this->GetName(); + // An empty map entry indicates we have been called recursively + // from the above block. + this->Makefile->GetCMakeInstance()->IssueMessage( + cmake::FATAL_ERROR, + "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.", + this->Target->GetBacktrace()); } - - cmGeneratorExpression ge; - cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName); - return cge->Evaluate(this->Makefile, config); + return i->second; } //---------------------------------------------------------------------------- diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 68e7a8a..15b3335 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -375,6 +375,10 @@ private: }; mutable std::map<std::string, LinkImplClosure> LinkImplClosureMap; + typedef std::pair<std::string, bool> OutputNameKey; + typedef std::map<OutputNameKey, std::string> OutputNameMapType; + mutable OutputNameMapType OutputNameMap; + public: std::vector<cmTarget const*> const& GetLinkImplementationClosure(const std::string& config) const; diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index 13a9afb..0f56c8e 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -93,11 +93,23 @@ bool cmGetFilenameComponentCommand else if (args[2] == "ABSOLUTE" || args[2] == "REALPATH") { + // If the path given is relative, evaluate it relative to the + // current source directory unless the user passes a different + // base directory. + std::string baseDir = this->Makefile->GetCurrentSourceDirectory(); + for(unsigned int i=3; i < args.size(); ++i) + { + if(args[i] == "BASE_DIR") + { + ++i; + if(i < args.size()) + { + baseDir = args[i]; + } + } + } // Collapse the path to its simplest form. - // If the path given is relative evaluate it relative to the - // current source directory. - result = cmSystemTools::CollapseFullPath( - filename, this->Makefile->GetCurrentSourceDirectory()); + result = cmSystemTools::CollapseFullPath(filename, baseDir); if(args[2] == "REALPATH") { // Resolve symlinks if possible diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index ca72939..3588853 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -57,7 +57,7 @@ void cmLocalVisualStudioGenerator::ComputeObjectFilenames( cmSourceFile const* sf = si->first; std::string objectNameLower = cmSystemTools::LowerCase( cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath())); - objectNameLower += ".obj"; + objectNameLower += this->GlobalGenerator->GetLanguageOutputExtension(*sf); counts[objectNameLower] += 1; } @@ -70,7 +70,7 @@ void cmLocalVisualStudioGenerator::ComputeObjectFilenames( cmSourceFile const* sf = si->first; std::string objectName = cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()); - objectName += ".obj"; + objectName += this->GlobalGenerator->GetLanguageOutputExtension(*sf); if(counts[cmSystemTools::LowerCase(objectName)] > 1) { const_cast<cmGeneratorTarget*>(gt)->AddExplicitObjectName(sf); diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-result.txt b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt new file mode 100644 index 0000000..bf592e7 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\): + Target 'empty1' OUTPUT_NAME depends on itself. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake new file mode 100644 index 0000000..5cb8050 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/OUTPUT_NAME-recursion.cmake @@ -0,0 +1,3 @@ +enable_language(C) +add_executable(empty1 empty.c) +set_property(TARGET empty1 PROPERTY OUTPUT_NAME $<TARGET_FILE_NAME:empty1>) diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake index 21fc851..0679024 100644 --- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake @@ -26,6 +26,7 @@ run_cmake(COMPILE_LANGUAGE-add_library) run_cmake(COMPILE_LANGUAGE-add_test) run_cmake(COMPILE_LANGUAGE-unknown-lang) run_cmake(TARGET_FILE-recursion) +run_cmake(OUTPUT_NAME-recursion) run_cmake(ImportedTarget-TARGET_PDB_FILE) if(LINKER_SUPPORTS_PDB) diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake index 7633be1..e780103 100644 --- a/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake +++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake @@ -1,3 +1,4 @@ enable_language(C) add_executable(empty1 empty.c) +set_property(TARGET empty1 PROPERTY OUTPUT_NAME $<TARGET_FILE_NAME:empty1>) set_property(TARGET empty1 PROPERTY RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:empty1>) diff --git a/Tests/RunCMake/get_filename_component/KnownComponents.cmake b/Tests/RunCMake/get_filename_component/KnownComponents.cmake index 386109f..d822258 100644 --- a/Tests/RunCMake/get_filename_component/KnownComponents.cmake +++ b/Tests/RunCMake/get_filename_component/KnownComponents.cmake @@ -38,6 +38,39 @@ check("ABSOLUTE .. in windows root" "${test_absolute}" "c:/path/to/filename.ext. list(APPEND non_cache_vars test_absolute) +# Test finding absolute paths from various base directories. + +get_filename_component(test_abs_base "testdir1" ABSOLUTE) +check("ABSOLUTE .. from default base" "${test_abs_base}" + "${CMAKE_CURRENT_SOURCE_DIR}/testdir1") + +get_filename_component(test_abs_base "../testdir2" ABSOLUTE + BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dummydir") +check("ABSOLUTE .. from dummy base to parent" "${test_abs_base}" + "${CMAKE_CURRENT_SOURCE_DIR}/testdir2") + +get_filename_component(test_abs_base "testdir3" ABSOLUTE + BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dummydir") +check("ABSOLUTE .. from dummy base to child" "${test_abs_base}" + "${CMAKE_CURRENT_SOURCE_DIR}/dummydir/testdir3") + +list(APPEND non_cache_vars test_abs_base) + +# Test finding absolute paths with CACHE parameter. (Note that more +# rigorous testing of the CACHE parameter comes later with PROGRAM). + +get_filename_component(test_abs_base_1 "testdir4" ABSOLUTE CACHE) +check("ABSOLUTE CACHE 1" "${test_abs_base_1}" + "${CMAKE_CURRENT_SOURCE_DIR}/testdir4") +list(APPEND cache_vars test_abs_base_1) + +get_filename_component(test_abs_base_2 "testdir5" ABSOLUTE + BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dummydir" + CACHE) +check("ABSOLUTE CACHE 2" "${test_abs_base_2}" + "${CMAKE_CURRENT_SOURCE_DIR}/dummydir/testdir5") +list(APPEND cache_vars test_abs_base_2) + # Test the PROGRAM component type. get_filename_component(test_program_name "/ arg1 arg2" PROGRAM) check("PROGRAM with no args output" "${test_program_name}" "/") |