diff options
79 files changed, 1453 insertions, 620 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index d315fcb..6ea5839 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -100,6 +100,10 @@ Properties on Targets /prop_tgt/COMPILE_DEFINITIONS /prop_tgt/COMPILE_FLAGS /prop_tgt/COMPILE_OPTIONS + /prop_tgt/COMPILE_PDB_NAME + /prop_tgt/COMPILE_PDB_NAME_CONFIG + /prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY + /prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG /prop_tgt/CONFIG_OUTPUT_NAME /prop_tgt/CONFIG_POSTFIX /prop_tgt/DEBUG_POSTFIX diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index c4ae193..5f2ba28 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -198,6 +198,8 @@ Variables that Control the Build /variable/CMAKE_AUTOUIC /variable/CMAKE_AUTOUIC_OPTIONS /variable/CMAKE_BUILD_WITH_INSTALL_RPATH + /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY + /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG /variable/CMAKE_CONFIG_POSTFIX /variable/CMAKE_DEBUG_POSTFIX /variable/CMAKE_EXE_LINKER_FLAGS_CONFIG diff --git a/Help/prop_tgt/COMPILE_PDB_NAME.rst b/Help/prop_tgt/COMPILE_PDB_NAME.rst new file mode 100644 index 0000000..24a9f62 --- /dev/null +++ b/Help/prop_tgt/COMPILE_PDB_NAME.rst @@ -0,0 +1,11 @@ +COMPILE_PDB_NAME +---------------- + +Output name for the MS debug symbol ``.pdb`` file generated by the +compiler while building source files. + +This property specifies the base name for the debug symbols file. +If not set, the default is unspecified. + +.. |PDB_XXX| replace:: :prop_tgt:`PDB_NAME` +.. include:: COMPILE_PDB_NOTE.txt diff --git a/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst new file mode 100644 index 0000000..e4077f5 --- /dev/null +++ b/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst @@ -0,0 +1,10 @@ +COMPILE_PDB_NAME_<CONFIG> +------------------------- + +Per-configuration output name for the MS debug symbol ``.pdb`` file +generated by the compiler while building source files. + +This is the configuration-specific version of :prop_tgt:`COMPILE_PDB_NAME`. + +.. |PDB_XXX| replace:: :prop_tgt:`PDB_NAME_<CONFIG>` +.. include:: COMPILE_PDB_NOTE.txt diff --git a/Help/prop_tgt/COMPILE_PDB_NOTE.txt b/Help/prop_tgt/COMPILE_PDB_NOTE.txt new file mode 100644 index 0000000..5941d72 --- /dev/null +++ b/Help/prop_tgt/COMPILE_PDB_NOTE.txt @@ -0,0 +1,8 @@ +.. note:: + The compiler-generated program database files are specified by the + ``/Fd`` compiler flag and are not the same as linker-generated + program database files specified by the ``/pdb`` linker flag. + Use the |PDB_XXX| property to specify the latter. + + This property is not implemented by the :generator:`Visual Studio 6` + generator. diff --git a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst new file mode 100644 index 0000000..34f49be --- /dev/null +++ b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst @@ -0,0 +1,13 @@ +COMPILE_PDB_OUTPUT_DIRECTORY +---------------------------- + +Output directory for the MS debug symbol ``.pdb`` file +generated by the compiler while building source files. + +This property specifies the directory into which the MS debug symbols +will be placed by the compiler. This property is initialized by the +value of the :variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY` variable +if it is set when a target is created. + +.. |PDB_XXX| replace:: :prop_tgt:`PDB_OUTPUT_DIRECTORY` +.. include:: COMPILE_PDB_NOTE.txt diff --git a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst new file mode 100644 index 0000000..52ef013 --- /dev/null +++ b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst @@ -0,0 +1,16 @@ +COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG> +------------------------------------- + +Per-configuration output directory for the MS debug symbol ``.pdb`` file +generated by the compiler while building source files. + +This is a per-configuration version of +:prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY`, +but multi-configuration generators (VS, Xcode) do NOT append a +per-configuration subdirectory to the specified directory. This +property is initialized by the value of the +:variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>` variable +if it is set when a target is created. + +.. |PDB_XXX| replace:: :prop_tgt:`PDB_OUTPUT_DIRECTORY_<CONFIG>` +.. include:: COMPILE_PDB_NOTE.txt diff --git a/Help/prop_tgt/PDB_NAME.rst b/Help/prop_tgt/PDB_NAME.rst index e8fc3be..479dec3 100644 --- a/Help/prop_tgt/PDB_NAME.rst +++ b/Help/prop_tgt/PDB_NAME.rst @@ -7,7 +7,5 @@ linker for an executable or shared library target. This property specifies the base name for the debug symbols file. If not set, the logical target name is used by default. +.. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_NAME` .. include:: PDB_NOTE.txt - -This property is not implemented by the :generator:`Visual Studio 6` -generator. diff --git a/Help/prop_tgt/PDB_NAME_CONFIG.rst b/Help/prop_tgt/PDB_NAME_CONFIG.rst index c846b57..cb3121c 100644 --- a/Help/prop_tgt/PDB_NAME_CONFIG.rst +++ b/Help/prop_tgt/PDB_NAME_CONFIG.rst @@ -6,5 +6,5 @@ generated by the linker for an executable or shared library target. This is the configuration-specific version of :prop_tgt:`PDB_NAME`. -This property is not implemented by the :generator:`Visual Studio 6` -generator. +.. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_NAME_<CONFIG>` +.. include:: PDB_NOTE.txt diff --git a/Help/prop_tgt/PDB_NOTE.txt b/Help/prop_tgt/PDB_NOTE.txt index e55aba2..f90ea81 100644 --- a/Help/prop_tgt/PDB_NOTE.txt +++ b/Help/prop_tgt/PDB_NOTE.txt @@ -3,6 +3,10 @@ is invoked to produce them so they have no linker-generated ``.pdb`` file containing debug symbols. - The compiler-generated program database files specified by the MSVC - ``/Fd`` flag are not the same as linker-generated program database - files and so are not influenced by this property. + The linker-generated program database files are specified by the + ``/pdb`` linker flag and are not the same as compiler-generated + program database files specified by the ``/Fd`` compiler flag. + Use the |COMPILE_PDB_XXX| property to specify the latter. + + This property is not implemented by the :generator:`Visual Studio 6` + generator. diff --git a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY.rst index 9a863a1..730cf57 100644 --- a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY.rst +++ b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY.rst @@ -9,7 +9,5 @@ will be placed by the linker. This property is initialized by the value of the :variable:`CMAKE_PDB_OUTPUT_DIRECTORY` variable if it is set when a target is created. +.. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY` .. include:: PDB_NOTE.txt - -This property is not implemented by the :generator:`Visual Studio 6` -generator. diff --git a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst index caec2de..6037fa0 100644 --- a/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst +++ b/Help/prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG.rst @@ -11,5 +11,5 @@ property is initialized by the value of the :variable:`CMAKE_PDB_OUTPUT_DIRECTORY_<CONFIG>` variable if it is set when a target is created. -This property is not implemented by the :generator:`Visual Studio 6` -generator. +.. |COMPILE_PDB_XXX| replace:: :prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>` +.. include:: PDB_NOTE.txt diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst new file mode 100644 index 0000000..e4cc01e --- /dev/null +++ b/Help/release/dev/0-sample-topic.rst @@ -0,0 +1,7 @@ +0-sample-topic +-------------- + +* This is a sample release note for the change in a topic. + Developers should add similar notes for each topic branch + making a noteworthy change. Each document should be named + and titled to match the topic name to avoid merge conflicts. diff --git a/Help/release/dev/faster-parsers.rst b/Help/release/dev/faster-parsers.rst new file mode 100644 index 0000000..c2a8bfb --- /dev/null +++ b/Help/release/dev/faster-parsers.rst @@ -0,0 +1,6 @@ +faster-parsers +-------------- + +* The :manual:`cmake-language(7)` internal implementation of generator + expression and list expansion parsers have been optimized and shows + non-trivial speedup on large projects. diff --git a/Help/release/dev/msvc-compiler-pdb-files.rst b/Help/release/dev/msvc-compiler-pdb-files.rst new file mode 100644 index 0000000..d06d202 --- /dev/null +++ b/Help/release/dev/msvc-compiler-pdb-files.rst @@ -0,0 +1,10 @@ +msvc-compiler-pdb-files +----------------------- + +* New :prop_tgt:`COMPILE_PDB_NAME` and + :prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY` target properties + were introduced to specify the MSVC compiler program database + file location (``cl /Fd``). This complements the existing + :prop_tgt:`PDB_NAME` and :prop_tgt:`PDB_OUTPUT_DIRECTORY` + target properties that specify the linker program database + file location (``link /pdb``). diff --git a/Help/release/index.rst b/Help/release/index.rst index 752c568..15ce065 100644 --- a/Help/release/index.rst +++ b/Help/release/index.rst @@ -5,6 +5,8 @@ CMake Release Notes This file should include the adjacent "dev.txt" file in development versions but not in release versions. +.. include:: dev.txt + Releases ======== diff --git a/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY.rst b/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY.rst new file mode 100644 index 0000000..ea33c7d --- /dev/null +++ b/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY.rst @@ -0,0 +1,8 @@ +CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY +---------------------------------- + +Output directory for MS debug symbol ``.pdb`` files +generated by the compiler while building source files. + +This variable is used to initialize the +:prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY` property on all the targets. diff --git a/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst new file mode 100644 index 0000000..fdeb9ab --- /dev/null +++ b/Help/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst @@ -0,0 +1,11 @@ +CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG> +------------------------------------------- + +Per-configuration output directory for MS debug symbol ``.pdb`` files +generated by the compiler while building source files. + +This is a per-configuration version of +:variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY`. +This variable is used to initialize the +:prop_tgt:`COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>` +property on all the targets. diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 0df51a8..1e83163 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -54,6 +54,7 @@ # [BINARY_DIR dir] # Specify build dir location # [BUILD_COMMAND cmd...] # Command to drive the native build # [BUILD_IN_SOURCE 1] # Use source dir for build dir +# [BUILD_ALWAYS 1] # No stamp file, build step always runs # #--Install step--------------- # [INSTALL_DIR dir] # Installation prefix # [INSTALL_COMMAND cmd...] # Command to drive install after build @@ -1716,10 +1717,18 @@ function(_ep_add_build_command name) set(log "") endif() + get_property(build_always TARGET ${name} PROPERTY _EP_BUILD_ALWAYS) + if(build_always) + set(always 1) + else() + set(always 0) + endif() + ExternalProject_Add_Step(${name} build COMMAND ${cmd} WORKING_DIRECTORY ${binary_dir} DEPENDEES configure + ALWAYS ${always} ${log} ) endfunction() diff --git a/Modules/FindHg.cmake b/Modules/FindHg.cmake index a1fb33f..c418afd 100644 --- a/Modules/FindHg.cmake +++ b/Modules/FindHg.cmake @@ -2,7 +2,7 @@ # FindHg # ------ # -# +# Extract information from a mercurial working copy. # # The module defines the following variables: # @@ -12,6 +12,20 @@ # HG_FOUND - true if the command line client was found # HG_VERSION_STRING - the version of mercurial found # +# If the command line client executable is found the following macro is defined: +# +# :: +# +# HG_WC_INFO(<dir> <var-prefix>) +# +# Hg_WC_INFO extracts information of a mercurial working copy +# at a given location. This macro defines the following variables: +# +# :: +# +# <var-prefix>_WC_CHANGESET - current changeset +# <var-prefix>_WC_REVISION - current revision +# # Example usage: # # :: @@ -19,11 +33,15 @@ # find_package(Hg) # if(HG_FOUND) # message("hg found: ${HG_EXECUTABLE}") +# HG_WC_INFO(${PROJECT_SOURCE_DIR} Project) +# message("Current revision is ${Project_WC_REVISION}") +# message("Current changeset is ${Project_WC_CHANGESET}") # endif() #============================================================================= # Copyright 2010-2012 Kitware, Inc. # Copyright 2012 Rolf Eike Beer <eike@sf-mail.de> +# Copyright 2014 Matthaeus G. Chajdas # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. @@ -37,6 +55,8 @@ find_program(HG_EXECUTABLE NAMES hg + PATHS + [HKEY_LOCAL_MACHINE\\Software\\TortoiseHG] PATH_SUFFIXES Mercurial DOC "hg command line client" ) @@ -51,6 +71,21 @@ if(HG_EXECUTABLE) set(HG_VERSION_STRING "${CMAKE_MATCH_1}") endif() unset(hg_version) + + macro(HG_WC_INFO dir prefix) + execute_process(COMMAND ${HG_EXECUTABLE} id -i -n + WORKING_DIRECTORY ${dir} + RESULT_VARIABLE hg_id_result + ERROR_VARIABLE hg_id_error + OUTPUT_VARIABLE ${prefix}_WC_DATA + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT ${hg_id_result} EQUAL 0) + message(SEND_ERROR "Command \"${HG_EXECUTBALE} id -n\" in directory ${dir} failed with output:\n${hg_id_error}") + endif() + + string(REGEX REPLACE "([0-9a-f]+)\\+? [0-9]+\\+?" "\\1" ${prefix}_WC_CHANGESET ${${prefix}_WC_DATA}) + string(REGEX REPLACE "[0-9a-f]+\\+? ([0-9]+)\\+?" "\\1" ${prefix}_WC_REVISION ${${prefix}_WC_DATA}) + endmacro(HG_WC_INFO) endif() # Handle the QUIETLY and REQUIRED arguments and set HG_FOUND to TRUE if diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index e29aaf4..5732170 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -241,7 +241,7 @@ macro(__windows_compiler_msvc lang) set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_LINKER> /lib ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ") set(CMAKE_${lang}_COMPILE_OBJECT - "<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} <FLAGS> <DEFINES> /Fo<OBJECT> /Fd<OBJECT_DIR>/${_FS_${lang}} -c <SOURCE>${CMAKE_END_TEMP_FILE}") + "<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} <FLAGS> <DEFINES> /Fo<OBJECT> /Fd<TARGET_COMPILE_PDB>${_FS_${lang}} -c <SOURCE>${CMAKE_END_TEMP_FILE}") set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} <FLAGS> <DEFINES> -E <SOURCE>${CMAKE_END_TEMP_FILE}") set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake index 11ca205..4ae6f81 100644 --- a/Modules/UseSWIG.cmake +++ b/Modules/UseSWIG.cmake @@ -85,9 +85,6 @@ macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile) set(${outfiles} "") get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename ${infile} SWIG_MODULE_NAME) - if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND") - get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${infile}" NAME_WE) - endif() foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSION}) set(${outfiles} ${${outfiles}} "${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}.${it}") @@ -103,6 +100,10 @@ macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile) get_source_file_property(swig_source_file_generated ${infile} GENERATED) get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS) get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS) + get_source_file_property(_SWIG_MODULE_NAME ${infile} SWIG_MODULE_NAME) + if ( NOT _SWIG_MODULE_NAME ) + set_source_files_properties(${infile} PROPERTIES SWIG_MODULE_NAME ${name}) + endif () if("${swig_source_file_flags}" STREQUAL "NOTFOUND") set(swig_source_file_flags "") endif() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 5ce43f5..a1ae3b3 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 0) -set(CMake_VERSION_PATCH 0) -set(CMake_VERSION_RC 1) +set(CMake_VERSION_PATCH 20140226) +#set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index 7d9c034..cd3bd57 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -587,8 +587,7 @@ void cmCTestLaunch::DumpFileToXML(std::ostream& fxml, while(cmSystemTools::GetLineFromStream(fin, line)) { - if(OptionFilterPrefix.size() && cmSystemTools::StringStartsWith( - line.c_str(), OptionFilterPrefix.c_str())) + if(MatchesFilterPrefix(line)) { continue; } @@ -676,6 +675,11 @@ bool cmCTestLaunch::ScrapeLog(std::string const& fname) std::string line; while(cmSystemTools::GetLineFromStream(fin, line)) { + if(MatchesFilterPrefix(line)) + { + continue; + } + if(this->Match(line.c_str(), this->RegexWarning) && !this->Match(line.c_str(), this->RegexWarningSuppress)) { @@ -701,6 +705,17 @@ bool cmCTestLaunch::Match(std::string const& line, } //---------------------------------------------------------------------------- +bool cmCTestLaunch::MatchesFilterPrefix(std::string const& line) const +{ + if(this->OptionFilterPrefix.size() && cmSystemTools::StringStartsWith( + line.c_str(), this->OptionFilterPrefix.c_str())) + { + return true; + } + return false; +} + +//---------------------------------------------------------------------------- int cmCTestLaunch::Main(int argc, const char* const argv[]) { if(argc == 2) diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h index a86a9df..f680d19 100644 --- a/Source/CTest/cmCTestLaunch.h +++ b/Source/CTest/cmCTestLaunch.h @@ -88,6 +88,7 @@ private: bool ScrapeLog(std::string const& fname); bool Match(std::string const& line, std::vector<cmsys::RegularExpression>& regexps); + bool MatchesFilterPrefix(std::string const& line) const; // Methods to generate the xml fragment. void WriteXML(); diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 2e66d78..cd30546 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -157,17 +157,24 @@ cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() std::string cmGeneratorExpression::StripEmptyListElements( const std::string &input) { + if (input.find(';') == input.npos) + { + return input; + } std::string result; + result.reserve(input.size()); const char *c = input.c_str(); + const char *last = c; bool skipSemiColons = true; for ( ; *c; ++c) { - if(c[0] == ';') + if(*c == ';') { if(skipSemiColons) { - continue; + result.append(last, c - last); + last = c + 1; } skipSemiColons = true; } @@ -175,8 +182,8 @@ std::string cmGeneratorExpression::StripEmptyListElements( { skipSemiColons = false; } - result += *c; } + result.append(last); if (!result.empty() && *(result.end() - 1) == ';') { diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 7036992..bdefcfb 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -800,7 +800,7 @@ static const char* targetPropertyTransitiveWhitelist[] = { #undef TRANSITIVE_PROPERTY_NAME -std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, +std::string getLinkedTargetsContent(const std::vector<cmTarget*> &targets, cmTarget const* target, cmTarget const* headTarget, cmGeneratorExpressionContext *context, @@ -811,23 +811,21 @@ std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, std::string sep; std::string depString; - for (std::vector<std::string>::const_iterator - it = libraries.begin(); - it != libraries.end(); ++it) + for (std::vector<cmTarget*>::const_iterator + it = targets.begin(); + it != targets.end(); ++it) { - if (*it == target->GetName()) + if (*it == target) { // Broken code can have a target in its own link interface. // Don't follow such link interface entries so as not to create a // self-referencing loop. continue; } - if (context->Makefile->FindTargetToUse(*it)) - { - depString += - sep + "$<TARGET_PROPERTY:" + *it + "," + interfacePropertyName + ">"; - sep = ";"; - } + depString += + sep + "$<TARGET_PROPERTY:" + + (*it)->GetName() + "," + interfacePropertyName + ">"; + sep = ";"; } cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString); std::string linkedTargetsContent = cge->Evaluate(context->Makefile, @@ -843,6 +841,27 @@ std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, return linkedTargetsContent; } +std::string getLinkedTargetsContent(const std::vector<std::string> &libraries, + cmTarget const* target, + cmTarget const* headTarget, + cmGeneratorExpressionContext *context, + cmGeneratorExpressionDAGChecker *dagChecker, + const std::string &interfacePropertyName) +{ + std::vector<cmTarget*> tgts; + for (std::vector<std::string>::const_iterator + it = libraries.begin(); + it != libraries.end(); ++it) + { + if (cmTarget *tgt = context->Makefile->FindTargetToUse(*it)) + { + tgts.push_back(tgt); + } + } + return getLinkedTargetsContent(tgts, target, headTarget, context, + dagChecker, interfacePropertyName); +} + //---------------------------------------------------------------------------- static const struct TargetPropertyNode : public cmGeneratorExpressionNode { @@ -1065,13 +1084,13 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode cmStrCmp(propertyName)) != transEnd) { - std::vector<std::string> libs; - target->GetTransitivePropertyLinkLibraries(context->Config, - headTarget, libs); - if (!libs.empty()) + std::vector<cmTarget*> tgts; + target->GetTransitivePropertyTargets(context->Config, + headTarget, tgts); + if (!tgts.empty()) { linkedTargetsContent = - getLinkedTargetsContent(libs, target, + getLinkedTargetsContent(tgts, target, headTarget, context, &dagChecker, interfacePropertyName); @@ -1080,9 +1099,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode else if (std::find_if(transBegin, transEnd, cmStrCmp(interfacePropertyName)) != transEnd) { - const cmTarget::LinkImplementation *impl = target->GetLinkImplementation( - context->Config, - headTarget); + const cmTarget::LinkImplementation *impl + = target->GetLinkImplementationLibraries(context->Config, + headTarget); if(impl) { linkedTargetsContent = diff --git a/Source/cmGeneratorExpressionLexer.cxx b/Source/cmGeneratorExpressionLexer.cxx index cd71ec0..117a24e 100644 --- a/Source/cmGeneratorExpressionLexer.cxx +++ b/Source/cmGeneratorExpressionLexer.cxx @@ -42,42 +42,42 @@ cmGeneratorExpressionLexer::Tokenize(const char *input) const char *upto = c; for ( ; *c; ++c) - { - if(c[0] == '$' && c[1] == '<') { - InsertText(upto, c, result); - upto = c; - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::BeginExpression, upto, 2)); - upto = c + 2; - ++c; - SawBeginExpression = true; - } - else if(c[0] == '>') - { - InsertText(upto, c, result); - upto = c; - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::EndExpression, upto, 1)); - upto = c + 1; - SawGeneratorExpression = SawBeginExpression; - } - else if(c[0] == ':') - { - InsertText(upto, c, result); - upto = c; - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::ColonSeparator, upto, 1)); - upto = c + 1; - } - else if(c[0] == ',') - { - InsertText(upto, c, result); - upto = c; - result.push_back(cmGeneratorExpressionToken( - cmGeneratorExpressionToken::CommaSeparator, upto, 1)); - upto = c + 1; - } + switch(*c) + { + case '$': + if(c[1] == '<') + { + InsertText(upto, c, result); + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::BeginExpression, c, 2)); + upto = c + 2; + ++c; + SawBeginExpression = true; + } + break; + case '>': + InsertText(upto, c, result); + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::EndExpression, c, 1)); + upto = c + 1; + SawGeneratorExpression = SawBeginExpression; + break; + case ':': + InsertText(upto, c, result); + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::ColonSeparator, c, 1)); + upto = c + 1; + break; + case ',': + InsertText(upto, c, result); + result.push_back(cmGeneratorExpressionToken( + cmGeneratorExpressionToken::CommaSeparator, c, 1)); + upto = c + 1; + break; + default: + break; + } } InsertText(upto, c, result); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 175bb0e..a7b2fb6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -25,7 +25,196 @@ #include "assert.h" //---------------------------------------------------------------------------- -cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t) +void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib, + cmTarget *target, cmake *cm) +{ + if(!badObjLib.empty()) + { + cmOStringStream e; + e << "OBJECT library \"" << target->GetName() << "\" contains:\n"; + for(std::vector<cmSourceFile*>::const_iterator i = badObjLib.begin(); + i != badObjLib.end(); ++i) + { + e << " " << (*i)->GetLocation().GetName() << "\n"; + } + e << "but may contain only headers and sources that compile."; + cm->IssueMessage(cmake::FATAL_ERROR, e.str(), + target->GetBacktrace()); + } +} + +struct ObjectSourcesTag {}; +struct CustomCommandsTag {}; +struct ExtraSourcesTag {}; +struct HeaderSourcesTag {}; +struct ExternalObjectsTag {}; +struct IDLSourcesTag {}; +struct ResxTag {}; +struct ModuleDefinitionFileTag {}; + +#if !defined(_MSC_VER) || _MSC_VER >= 1310 +template<typename Tag, typename OtherTag> +struct IsSameTag +{ + enum { + Result = false + }; +}; + +template<typename Tag> +struct IsSameTag<Tag, Tag> +{ + enum { + Result = true + }; +}; +#else +struct IsSameTagBase +{ + typedef char (&no_type)[1]; + typedef char (&yes_type)[2]; + template<typename T> struct Check; + template<typename T> static yes_type check(Check<T>*, Check<T>*); + static no_type check(...); +}; +template<typename Tag1, typename Tag2> +struct IsSameTag: public IsSameTagBase +{ + enum { + Result = (sizeof(check(static_cast< Check<Tag1>* >(0), + static_cast< Check<Tag2>* >(0))) == + sizeof(yes_type)) + }; +}; +#endif + +template<bool> +struct DoAccept +{ + template <typename T> static void Do(T&, cmSourceFile*) {} +}; + +template<> +struct DoAccept<true> +{ + static void Do(std::vector<cmSourceFile*>& files, cmSourceFile* f) + { + files.push_back(f); + } + static void Do(cmGeneratorTarget::ResxData& data, cmSourceFile* f) + { + // Build and save the name of the corresponding .h file + // This relationship will be used later when building the project files. + // Both names would have been auto generated from Visual Studio + // where the user supplied the file name and Visual Studio + // appended the suffix. + std::string resx = f->GetFullPath(); + std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; + data.ExpectedResxHeaders.insert(hFileName); + data.ResxSources.push_back(f); + } + static void Do(std::string& data, cmSourceFile* f) + { + data = f->GetFullPath(); + } +}; + +//---------------------------------------------------------------------------- +template<typename Tag, typename DataType = std::vector<cmSourceFile*> > +struct TagVisitor +{ + DataType& Data; + std::vector<cmSourceFile*> BadObjLibFiles; + cmTarget *Target; + cmGlobalGenerator *GlobalGenerator; + cmsys::RegularExpression Header; + bool IsObjLib; + + TagVisitor(cmTarget *target, DataType& data) + : Data(data), Target(target), + GlobalGenerator(target->GetMakefile() + ->GetLocalGenerator()->GetGlobalGenerator()), + Header(CM_HEADER_REGEX), + IsObjLib(target->GetType() == cmTarget::OBJECT_LIBRARY) + { + } + + ~TagVisitor() + { + reportBadObjLib(this->BadObjLibFiles, this->Target, + this->GlobalGenerator->GetCMakeInstance()); + } + + void Accept(cmSourceFile *sf) + { + std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); + if(sf->GetCustomCommand()) + { + DoAccept<IsSameTag<Tag, CustomCommandsTag>::Result>::Do(this->Data, sf); + } + else if(this->Target->GetType() == cmTarget::UTILITY) + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + } + else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY")) + { + DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf); + } + else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT")) + { + DoAccept<IsSameTag<Tag, ExternalObjectsTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(sf->GetLanguage()) + { + DoAccept<IsSameTag<Tag, ObjectSourcesTag>::Result>::Do(this->Data, sf); + } + else if(ext == "def") + { + DoAccept<IsSameTag<Tag, ModuleDefinitionFileTag>::Result>::Do(this->Data, + sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(ext == "idl") + { + DoAccept<IsSameTag<Tag, IDLSourcesTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(ext == "resx") + { + DoAccept<IsSameTag<Tag, ResxTag>::Result>::Do(this->Data, sf); + } + else if(this->Header.find(sf->GetFullPath().c_str())) + { + DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf); + } + else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + } + else + { + DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf); + if(this->IsObjLib && ext != "txt") + { + this->BadObjLibFiles.push_back(sf); + } + } + } +}; + +//---------------------------------------------------------------------------- +cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t), + SourceFileFlagsConstructed(false) { this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = this->Makefile->GetLocalGenerator(); @@ -62,19 +251,12 @@ cmGeneratorTarget::GetSourceDepends(cmSourceFile* sf) const return 0; } -static void handleSystemIncludesDep(cmMakefile *mf, const std::string &name, +static void handleSystemIncludesDep(cmMakefile *mf, cmTarget* depTgt, const char *config, cmTarget *headTarget, cmGeneratorExpressionDAGChecker *dagChecker, std::vector<std::string>& result, bool excludeImported) { - cmTarget* depTgt = mf->FindTargetToUse(name); - - if (!depTgt) - { - return; - } - cmListFileBacktrace lfbt; if (const char* dirs = @@ -102,11 +284,34 @@ static void handleSystemIncludesDep(cmMakefile *mf, const std::string &name, } } +#define IMPLEMENT_VISIT_IMPL(DATA, DATATYPE) \ + { \ + std::vector<cmSourceFile*> sourceFiles; \ + this->Target->GetSourceFiles(sourceFiles); \ + TagVisitor<DATA ## Tag DATATYPE> visitor(this->Target, data); \ + for(std::vector<cmSourceFile*>::const_iterator si = sourceFiles.begin(); \ + si != sourceFiles.end(); ++si) \ + { \ + visitor.Accept(*si); \ + } \ + } \ + + +#define IMPLEMENT_VISIT(DATA) \ + IMPLEMENT_VISIT_IMPL(DATA, EMPTY) \ + +#define EMPTY +#define COMMA , + //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetObjectSources(std::vector<cmSourceFile*> &objs) const +cmGeneratorTarget::GetObjectSources(std::vector<cmSourceFile*> &data) const { - objs = this->ObjectSources; + IMPLEMENT_VISIT(ObjectSources); + if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY) + { + this->ObjectSources = data; + } } //---------------------------------------------------------------------------- @@ -135,49 +340,53 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& data) const { - srcs = this->ResxSources; + IMPLEMENT_VISIT(IDLSources); } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& srcs) const +void +cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& data) const { - srcs = this->IDLSources; + IMPLEMENT_VISIT(HeaderSources); } //---------------------------------------------------------------------------- -void -cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& data) const { - srcs = this->HeaderSources; + IMPLEMENT_VISIT(ExtraSources); } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& srcs) const +void +cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& data) const { - srcs = this->ExtraSources; + IMPLEMENT_VISIT(CustomCommands); } //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& srcs) const +cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& data) const { - srcs = this->CustomCommands; + IMPLEMENT_VISIT(ExternalObjects); } //---------------------------------------------------------------------------- void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& srcs) const { - srcs = this->ExpectedResxHeaders; + ResxData data; + IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData) + srcs = data.ExpectedResxHeaders; } //---------------------------------------------------------------------------- -void -cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& srcs) const +void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile*>& srcs) const { - srcs = this->ExternalObjects; + ResxData data; + IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData) + srcs = data.ResxSources; } //---------------------------------------------------------------------------- @@ -224,26 +433,25 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir, &dagChecker), result); } - std::set<cmStdString> uniqueDeps; + std::set<cmTarget*> uniqueDeps; for(std::vector<std::string>::const_iterator li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) { - if (uniqueDeps.insert(*li).second) + cmTarget* tgt = this->Makefile->FindTargetToUse(*li); + if (!tgt) { - cmTarget* tgt = this->Makefile->FindTargetToUse(*li); - - if (!tgt) - { - continue; - } + continue; + } - handleSystemIncludesDep(this->Makefile, *li, config, this->Target, + if (uniqueDeps.insert(tgt).second) + { + handleSystemIncludesDep(this->Makefile, tgt, config, this->Target, &dagChecker, result, excludeImported); - std::vector<std::string> deps; - tgt->GetTransitivePropertyLinkLibraries(config, this->Target, deps); + std::vector<cmTarget*> deps; + tgt->GetTransitivePropertyTargets(config, this->Target, deps); - for(std::vector<std::string>::const_iterator di = deps.begin(); + for(std::vector<cmTarget*>::const_iterator di = deps.begin(); di != deps.end(); ++di) { if (uniqueDeps.insert(*di).second) @@ -290,102 +498,6 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const } //---------------------------------------------------------------------------- -void cmGeneratorTarget::ClassifySources() -{ - cmsys::RegularExpression header(CM_HEADER_REGEX); - - cmTarget::TargetType targetType = this->Target->GetType(); - bool isObjLib = targetType == cmTarget::OBJECT_LIBRARY; - - std::vector<cmSourceFile*> badObjLib; - std::vector<cmSourceFile*> sources; - this->Target->GetSourceFiles(sources); - for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); - si != sources.end(); ++si) - { - cmSourceFile* sf = *si; - std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); - if(sf->GetCustomCommand()) - { - this->CustomCommands.push_back(sf); - } - else if(targetType == cmTarget::UTILITY) - { - this->ExtraSources.push_back(sf); - } - else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY")) - { - this->HeaderSources.push_back(sf); - } - else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT")) - { - this->ExternalObjects.push_back(sf); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(sf->GetLanguage()) - { - this->ObjectSources.push_back(sf); - } - else if(ext == "def") - { - this->ModuleDefinitionFile = sf->GetFullPath(); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(ext == "idl") - { - this->IDLSources.push_back(sf); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(ext == "resx") - { - // Build and save the name of the corresponding .h file - // This relationship will be used later when building the project files. - // Both names would have been auto generated from Visual Studio - // where the user supplied the file name and Visual Studio - // appended the suffix. - std::string resx = sf->GetFullPath(); - std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; - this->ExpectedResxHeaders.insert(hFileName); - this->ResxSources.push_back(sf); - } - else if(header.find(sf->GetFullPath().c_str())) - { - this->HeaderSources.push_back(sf); - } - else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) - { - // We only get here if a source file is not an external object - // and has an extension that is listed as an ignored file type. - // No message or diagnosis should be given. - this->ExtraSources.push_back(sf); - } - else - { - this->ExtraSources.push_back(sf); - if(isObjLib && ext != "txt") - { - badObjLib.push_back(sf); - } - } - } - - if(!badObjLib.empty()) - { - cmOStringStream e; - e << "OBJECT library \"" << this->Target->GetName() << "\" contains:\n"; - for(std::vector<cmSourceFile*>::iterator i = badObjLib.begin(); - i != badObjLib.end(); ++i) - { - e << " " << (*i)->GetLocation().GetName() << "\n"; - } - e << "but may contain only headers and sources that compile."; - this->GlobalGenerator->GetCMakeInstance() - ->IssueMessage(cmake::FATAL_ERROR, e.str(), - this->Target->GetBacktrace()); - } -} - -//---------------------------------------------------------------------------- void cmGeneratorTarget::LookupObjectLibraries() { std::vector<std::string> const& objLibs = @@ -438,6 +550,14 @@ void cmGeneratorTarget::LookupObjectLibraries() } //---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetModuleDefinitionFile() const +{ + std::string data; + IMPLEMENT_VISIT_IMPL(ModuleDefinitionFile, COMMA std::string) + return data; +} + +//---------------------------------------------------------------------------- void cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs) const { @@ -876,3 +996,97 @@ bool cmStrictTargetComparison::operator()(cmTarget const* t1, } return nameResult < 0; } + +//---------------------------------------------------------------------------- +struct cmGeneratorTarget::SourceFileFlags +cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const +{ + struct SourceFileFlags flags; + this->ConstructSourceFileFlags(); + std::map<cmSourceFile const*, SourceFileFlags>::iterator si = + this->SourceFlagsMap.find(sf); + if(si != this->SourceFlagsMap.end()) + { + flags = si->second; + } + else + { + // Handle the MACOSX_PACKAGE_LOCATION property on source files that + // were not listed in one of the other lists. + if(const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) + { + flags.MacFolder = location; + if(strcmp(location, "Resources") == 0) + { + flags.Type = cmGeneratorTarget::SourceFileTypeResource; + } + else + { + flags.Type = cmGeneratorTarget::SourceFileTypeMacContent; + } + } + } + return flags; +} + +//---------------------------------------------------------------------------- +void cmGeneratorTarget::ConstructSourceFileFlags() const +{ + if(this->SourceFileFlagsConstructed) + { + return; + } + this->SourceFileFlagsConstructed = true; + + // Process public headers to mark the source files. + if(const char* files = this->Target->GetProperty("PUBLIC_HEADER")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "Headers"; + flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader; + } + } + } + + // Process private headers after public headers so that they take + // precedence if a file is listed in both. + if(const char* files = this->Target->GetProperty("PRIVATE_HEADER")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "PrivateHeaders"; + flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader; + } + } + } + + // Mark sources listed as resources. + if(const char* files = this->Target->GetProperty("RESOURCE")) + { + std::vector<std::string> relFiles; + cmSystemTools::ExpandListArgument(files, relFiles); + for(std::vector<std::string>::iterator it = relFiles.begin(); + it != relFiles.end(); ++it) + { + if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) + { + SourceFileFlags& flags = this->SourceFlagsMap[sf]; + flags.MacFolder = "Resources"; + flags.Type = cmGeneratorTarget::SourceFileTypeResource; + } + } + } +} diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index a4caba1..1e6ce64 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -52,7 +52,7 @@ public: cmLocalGenerator* LocalGenerator; cmGlobalGenerator const* GlobalGenerator; - std::string ModuleDefinitionFile; + std::string GetModuleDefinitionFile() const; /** Full path with trailing slash to the top-level directory holding object files for this target. Includes the build @@ -82,31 +82,56 @@ public: */ void TraceDependencies(); - void ClassifySources(); void LookupObjectLibraries(); /** Get sources that must be built before the given source. */ std::vector<cmSourceFile*> const* GetSourceDepends(cmSourceFile* sf) const; + /** + * Flags for a given source file as used in this target. Typically assigned + * via SET_TARGET_PROPERTIES when the property is a list of source files. + */ + enum SourceFileType + { + SourceFileTypeNormal, + SourceFileTypePrivateHeader, // is in "PRIVATE_HEADER" target property + SourceFileTypePublicHeader, // is in "PUBLIC_HEADER" target property + SourceFileTypeResource, // is in "RESOURCE" target property *or* + // has MACOSX_PACKAGE_LOCATION=="Resources" + SourceFileTypeMacContent // has MACOSX_PACKAGE_LOCATION!="Resources" + }; + struct SourceFileFlags + { + SourceFileFlags(): Type(SourceFileTypeNormal), MacFolder(0) {} + SourceFileFlags(SourceFileFlags const& r): + Type(r.Type), MacFolder(r.MacFolder) {} + SourceFileType Type; + const char* MacFolder; // location inside Mac content folders + }; + + struct SourceFileFlags + GetTargetSourceFileFlags(const cmSourceFile* sf) const; + + struct ResxData { + mutable std::set<std::string> ExpectedResxHeaders; + mutable std::vector<cmSourceFile*> ResxSources; + }; private: friend class cmTargetTraceDependencies; struct SourceEntry { std::vector<cmSourceFile*> Depends; }; typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType; SourceEntriesType SourceEntries; - std::vector<cmSourceFile*> CustomCommands; - std::vector<cmSourceFile*> ExtraSources; - std::vector<cmSourceFile*> HeaderSources; - std::vector<cmSourceFile*> ExternalObjects; - std::vector<cmSourceFile*> IDLSources; - std::vector<cmSourceFile*> ResxSources; std::map<cmSourceFile const*, std::string> Objects; std::set<cmSourceFile const*> ExplicitObjectName; - std::set<std::string> ExpectedResxHeaders; - std::vector<cmSourceFile*> ObjectSources; + mutable std::vector<cmSourceFile*> ObjectSources; std::vector<cmTarget*> ObjectLibraries; mutable std::map<std::string, std::vector<std::string> > SystemIncludesCache; + void ConstructSourceFileFlags() const; + mutable bool SourceFileFlagsConstructed; + mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap; + cmGeneratorTarget(cmGeneratorTarget const&); void operator=(cmGeneratorTarget const&); }; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 4f3328d..f76c6d1 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1148,12 +1148,6 @@ void cmGlobalGenerator::Generate() return; } - // Check that all targets are valid. - if(!this->CheckTargets()) - { - return; - } - this->FinalizeTargetCompileInfo(); #ifdef CMAKE_BUILD_WITH_CMAKE @@ -1306,35 +1300,6 @@ bool cmGlobalGenerator::ComputeTargetDepends() } //---------------------------------------------------------------------------- -bool cmGlobalGenerator::CheckTargets() -{ - // Make sure all targets can find their source files. - for(unsigned int i=0; i < this->LocalGenerators.size(); ++i) - { - cmTargets& targets = - this->LocalGenerators[i]->GetMakefile()->GetTargets(); - for(cmTargets::iterator ti = targets.begin(); - ti != targets.end(); ++ti) - { - cmTarget& target = ti->second; - if(target.GetType() == cmTarget::EXECUTABLE || - target.GetType() == cmTarget::STATIC_LIBRARY || - target.GetType() == cmTarget::SHARED_LIBRARY || - target.GetType() == cmTarget::MODULE_LIBRARY || - target.GetType() == cmTarget::OBJECT_LIBRARY || - target.GetType() == cmTarget::UTILITY) - { - if(!target.FindSourceFiles()) - { - return false; - } - } - } - } - return true; -} - -//---------------------------------------------------------------------------- void cmGlobalGenerator::CreateQtAutoGeneratorsTargets(AutogensType &autogens) { #ifdef CMAKE_BUILD_WITH_CMAKE @@ -1474,7 +1439,6 @@ void cmGlobalGenerator::ComputeGeneratorTargetObjects() continue; } cmGeneratorTarget* gt = ti->second; - gt->ClassifySources(); gt->LookupObjectLibraries(); this->ComputeTargetObjects(gt); } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 753eebf..b66f01e 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -340,7 +340,6 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; - bool CheckTargets(); typedef std::vector<std::pair<cmQtAutoGenerators, cmTarget const*> > AutogensType; void CreateQtAutoGeneratorsTargets(AutogensType& autogens); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 484b28f..004f7ac 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -713,22 +713,23 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, // Is this a resource file in this target? Add it to the resources group... // - cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf); - bool isResource = (tsFlags.Type == cmTarget::SourceFileTypeResource); + cmGeneratorTarget::SourceFileFlags tsFlags = + this->GetGeneratorTarget(&cmtarget)->GetTargetSourceFileFlags(sf); + bool isResource = tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource; // Is this a "private" or "public" framework header file? // Set the ATTRIBUTES attribute appropriately... // if(cmtarget.IsFrameworkOnApple()) { - if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) + if(tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Private")); settings->AddAttribute("ATTRIBUTES", attrs); isResource = true; } - else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader) + else if(tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader) { cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); attrs->AddObject(this->CreateString("Public")); @@ -973,6 +974,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { cmTarget& cmtarget = l->second; + cmGeneratorTarget* gtgt = this->GetGeneratorTarget(&cmtarget); // make sure ALL_BUILD, INSTALL, etc are only done once if(this->SpecialTargetEmitted(l->first.c_str())) @@ -1011,8 +1013,8 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType"); - cmTarget::SourceFileFlags tsFlags = - cmtarget.GetTargetSourceFileFlags(*i); + cmGeneratorTarget::SourceFileFlags tsFlags = + gtgt->GetTargetSourceFileFlags(*i); if(filetype && strcmp(filetype->GetString(), "compiled.mach-o.objfile") == 0) @@ -1020,12 +1022,12 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, externalObjFiles.push_back(xsf); } else if(this->IsHeaderFile(*i) || - (tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) || - (tsFlags.Type == cmTarget::SourceFileTypePublicHeader)) + (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) || + (tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader)) { headerFiles.push_back(xsf); } - else if(tsFlags.Type == cmTarget::SourceFileTypeResource) + else if(tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource) { resourceFiles.push_back(xsf); } @@ -1048,7 +1050,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, // the externalObjFiles above, except each one is not a cmSourceFile // within the target.) std::vector<std::string> objs; - this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs); + gtgt->UseObjectLibraries(objs); for(std::vector<std::string>::const_iterator oi = objs.begin(); oi != objs.end(); ++oi) { @@ -1138,9 +1140,9 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, for(std::vector<cmSourceFile*>::const_iterator i = classes.begin(); i != classes.end(); ++i) { - cmTarget::SourceFileFlags tsFlags = - cmtarget.GetTargetSourceFileFlags(*i); - if(tsFlags.Type == cmTarget::SourceFileTypeMacContent) + cmGeneratorTarget::SourceFileFlags tsFlags = + gtgt->GetTargetSourceFileFlags(*i); + if(tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) { bundleFiles[tsFlags.MacFolder].push_back(*i); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index aca195c..4266dd0 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -901,6 +901,13 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable, return replaceValues.TargetPDB; } } + if(replaceValues.TargetCompilePDB) + { + if(variable == "TARGET_COMPILE_PDB") + { + return replaceValues.TargetCompilePDB; + } + } if(replaceValues.DependencyFile ) { if(variable == "DEP_FILE") diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 9764813..0f7fd25 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -245,6 +245,7 @@ public: } cmTarget* CMTarget; const char* TargetPDB; + const char* TargetCompilePDB; const char* TargetVersionMajor; const char* TargetVersionMinor; const char* Language; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 212b06b..ce24d8d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -660,7 +660,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, switch(target.GetType()) { case cmTarget::OBJECT_LIBRARY: - targetBuilds = false; // TODO: PDB for object library? + targetBuilds = false; // no manifest tool for object library case cmTarget::STATIC_LIBRARY: projectType = "typeStaticLibrary"; configType = "4"; @@ -846,6 +846,17 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, targetOptions.OutputFlagMap(fout, "\t\t\t\t"); targetOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t", "\n", "CXX"); fout << "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"; + if(target.GetType() <= cmTarget::OBJECT_LIBRARY) + { + // Specify the compiler program database file if configured. + std::string pdb = target.GetCompilePDBPath(configName); + if(!pdb.empty()) + { + fout << "\t\t\t\tProgramDataBaseFileName=\"" + << this->ConvertToXMLOutputPathSingle(pdb.c_str()) + << "\"\n"; + } + } fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool tool = "VCCustomBuildTool"; if(this->FortranProject) diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 69b8092..03fdda2 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -129,7 +129,11 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) } } - std::string pdbOutputPath = this->Target->GetPDBDirectory(); + std::string compilePdbOutputPath = + this->Target->GetCompilePDBDirectory(this->ConfigName); + cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str()); + + std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName); cmSystemTools::MakeDirectory(pdbOutputPath.c_str()); pdbOutputPath += "/"; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index d6a0cd4..807aca8 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -321,7 +321,11 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules } } - std::string pdbOutputPath = this->Target->GetPDBDirectory(); + std::string compilePdbOutputPath = + this->Target->GetCompilePDBDirectory(this->ConfigName); + cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str()); + + std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName); cmSystemTools::MakeDirectory(pdbOutputPath.c_str()); pdbOutputPath += "/"; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index c3ca85d..e8a9fd1 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -624,9 +624,11 @@ cmMakefileTargetGenerator std::string targetOutPathReal; std::string targetOutPathPDB; + std::string targetOutPathCompilePDB; { std::string targetFullPathReal; std::string targetFullPathPDB; + std::string targetFullPathCompilePDB; if(this->Target->GetType() == cmTarget::EXECUTABLE || this->Target->GetType() == cmTarget::STATIC_LIBRARY || this->Target->GetType() == cmTarget::SHARED_LIBRARY || @@ -638,12 +640,26 @@ cmMakefileTargetGenerator targetFullPathPDB += "/"; targetFullPathPDB += this->Target->GetPDBName(this->ConfigName); } + if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY) + { + targetFullPathCompilePDB = + this->Target->GetCompilePDBPath(this->ConfigName); + if(targetFullPathCompilePDB.empty()) + { + targetFullPathCompilePDB = this->Target->GetSupportDirectory() + "/"; + } + } + targetOutPathReal = this->Convert(targetFullPathReal.c_str(), cmLocalGenerator::START_OUTPUT, cmLocalGenerator::SHELL); targetOutPathPDB = this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::NONE, cmLocalGenerator::SHELL); + targetOutPathCompilePDB = + this->Convert(targetFullPathCompilePDB.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); } cmLocalGenerator::RuleVariables vars; vars.RuleLauncher = "RULE_LAUNCH_COMPILE"; @@ -651,6 +667,7 @@ cmMakefileTargetGenerator vars.Language = lang; vars.Target = targetOutPathReal.c_str(); vars.TargetPDB = targetOutPathPDB.c_str(); + vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); vars.Source = sourceFile.c_str(); std::string shellObj = this->Convert(obj.c_str(), @@ -1650,9 +1667,10 @@ void cmMakefileTargetGenerator this->AppendTargetDepends(depends); // Add a dependency on the link definitions file, if any. - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - depends.push_back(this->GeneratorTarget->ModuleDefinitionFile); + depends.push_back(def); } // Add user-specified dependencies. @@ -2019,7 +2037,8 @@ void cmMakefileTargetGenerator::AddFortranFlags(std::string& flags) //---------------------------------------------------------------------------- void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags) { - if(this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(def.empty()) { return; } @@ -2035,8 +2054,7 @@ void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags) // Append the flag and value. Use ConvertToLinkReference to help // vs6's "cl -link" pass it to the linker. std::string flag = defFileFlag; - flag += (this->LocalGenerator->ConvertToLinkReference( - this->GeneratorTarget->ModuleDefinitionFile.c_str())); + flag += (this->LocalGenerator->ConvertToLinkReference(def.c_str())); this->LocalGenerator->AppendFlags(flags, flag.c_str()); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 900af8d..00b0441 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -320,6 +320,7 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID")) { std::string pdbPath; + std::string compilePdbPath; if(this->Target->GetType() == cmTarget::EXECUTABLE || this->Target->GetType() == cmTarget::STATIC_LIBRARY || this->Target->GetType() == cmTarget::SHARED_LIBRARY || @@ -329,11 +330,25 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const pdbPath += "/"; pdbPath += this->Target->GetPDBName(this->GetConfigName()); } + if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY) + { + compilePdbPath = this->Target->GetCompilePDBPath(this->GetConfigName()); + if(compilePdbPath.empty()) + { + compilePdbPath = this->Target->GetSupportDirectory() + "/"; + } + } vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( ConvertToNinjaPath(pdbPath.c_str()).c_str(), cmLocalGenerator::SHELL); + vars["TARGET_COMPILE_PDB"] = + this->GetLocalGenerator()->ConvertToOutputFormat( + ConvertToNinjaPath(compilePdbPath.c_str()).c_str(), + cmLocalGenerator::SHELL); + EnsureParentDirectoryExists(pdbPath); + EnsureParentDirectoryExists(compilePdbPath); return true; } return false; @@ -362,6 +377,7 @@ cmNinjaTargetGenerator vars.Object = "$out"; vars.Defines = "$DEFINES"; vars.TargetPDB = "$TARGET_PDB"; + vars.TargetCompilePDB = "$TARGET_COMPILE_PDB"; vars.ObjectDir = "$OBJECT_DIR"; cmMakefile* mf = this->GetMakefile(); @@ -498,10 +514,10 @@ cmNinjaTargetGenerator { this->WriteObjectBuildStatement(*si); } - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - this->ModuleDefinitionFile = this->ConvertToNinjaPath( - this->GeneratorTarget->ModuleDefinitionFile.c_str()); + this->ModuleDefinitionFile = this->ConvertToNinjaPath(def.c_str()); } { diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 9a340dc..78b59b3 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -20,7 +20,7 @@ cmOSXBundleGenerator:: cmOSXBundleGenerator(cmGeneratorTarget* target, const char* configName) - : Target(target->Target) + : GT(target) , Makefile(target->Target->GetMakefile()) , LocalGenerator(Makefile->GetLocalGenerator()) , ConfigName(configName) @@ -34,7 +34,7 @@ cmOSXBundleGenerator(cmGeneratorTarget* target, //---------------------------------------------------------------------------- bool cmOSXBundleGenerator::MustSkip() { - return !this->Target->HaveWellDefinedOutputFiles(); + return !this->GT->Target->HaveWellDefinedOutputFiles(); } //---------------------------------------------------------------------------- @@ -47,7 +47,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, // Compute bundle directory names. std::string out = outpath; out += "/"; - out += this->Target->GetAppBundleDirectory(this->ConfigName, false); + out += this->GT->Target->GetAppBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); @@ -57,9 +57,9 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, // to be set. std::string plist = outpath; plist += "/"; - plist += this->Target->GetAppBundleDirectory(this->ConfigName, true); + plist += this->GT->Target->GetAppBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; - this->LocalGenerator->GenerateAppleInfoPList(this->Target, + this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target, targetName.c_str(), plist.c_str()); this->Makefile->AddCMakeOutputFile(plist); @@ -77,20 +77,20 @@ void cmOSXBundleGenerator::CreateFramework( // Compute the location of the top-level foo.framework directory. std::string contentdir = outpath + "/" + - this->Target->GetFrameworkDirectory(this->ConfigName, true); + this->GT->Target->GetFrameworkDirectory(this->ConfigName, true); contentdir += "/"; std::string newoutpath = outpath + "/" + - this->Target->GetFrameworkDirectory(this->ConfigName, false); + this->GT->Target->GetFrameworkDirectory(this->ConfigName, false); - std::string frameworkVersion = this->Target->GetFrameworkVersion(); + std::string frameworkVersion = this->GT->Target->GetFrameworkVersion(); // Configure the Info.plist file into the Resources directory. this->MacContentFolders->insert("Resources"); std::string plist = newoutpath; plist += "/Resources/Info.plist"; std::string name = cmSystemTools::GetFilenameName(targetName); - this->LocalGenerator->GenerateFrameworkInfoPList(this->Target, + this->LocalGenerator->GenerateFrameworkInfoPList(this->GT->Target, name.c_str(), plist.c_str()); @@ -172,16 +172,16 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, // Compute bundle directory names. std::string out = root; out += "/"; - out += this->Target->GetCFBundleDirectory(this->ConfigName, false); + out += this->GT->Target->GetCFBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name // to be set. std::string plist = - this->Target->GetCFBundleDirectory(this->ConfigName, true); + this->GT->Target->GetCFBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; - this->LocalGenerator->GenerateAppleInfoPList(this->Target, + this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target, targetName.c_str(), plist.c_str()); this->Makefile->AddCMakeOutputFile(plist); @@ -199,9 +199,9 @@ GenerateMacOSXContentStatements(std::vector<cmSourceFile*> const& sources, for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); si != sources.end(); ++si) { - cmTarget::SourceFileFlags tsFlags = - this->Target->GetTargetSourceFileFlags(*si); - if(tsFlags.Type != cmTarget::SourceFileTypeNormal) + cmGeneratorTarget::SourceFileFlags tsFlags = + this->GT->GetTargetSourceFileFlags(*si); + if(tsFlags.Type != cmGeneratorTarget::SourceFileTypeNormal) { (*generator)(**si, tsFlags.MacFolder); } @@ -215,7 +215,7 @@ cmOSXBundleGenerator::InitMacOSXContentDirectory(const char* pkgloc) // Construct the full path to the content subdirectory. std::string macdir = - this->Target->GetMacContentDirectory(this->ConfigName, + this->GT->Target->GetMacContentDirectory(this->ConfigName, /*implib*/ false); macdir += "/"; macdir += pkgloc; diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h index 29b7611..2f36394 100644 --- a/Source/cmOSXBundleGenerator.h +++ b/Source/cmOSXBundleGenerator.h @@ -59,7 +59,7 @@ private: bool MustSkip(); private: - cmTarget* Target; + cmGeneratorTarget* GT; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; const char* ConfigName; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index ff05975..7cc63bb 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1044,7 +1044,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg, bool emptyArgs) { // If argument is empty, it is an empty list. - if(arg.length() == 0 && !emptyArgs) + if(!emptyArgs && arg.empty()) { return; } @@ -1054,10 +1054,11 @@ void cmSystemTools::ExpandListArgument(const std::string& arg, newargs.push_back(arg); return; } - std::vector<char> newArgVec; + std::string newArg; + const char *last = arg.c_str(); // Break the string at non-escaped semicolons not nested in []. int squareNesting = 0; - for(const char* c = arg.c_str(); *c; ++c) + for(const char* c = last; *c; ++c) { switch(*c) { @@ -1065,34 +1066,21 @@ void cmSystemTools::ExpandListArgument(const std::string& arg, { // We only want to allow escaping of semicolons. Other // escapes should not be processed here. - ++c; - if(*c == ';') - { - newArgVec.push_back(*c); - } - else + const char* next = c + 1; + if(*next == ';') { - newArgVec.push_back('\\'); - if(*c) - { - newArgVec.push_back(*c); - } - else - { - // Terminate the loop properly. - --c; - } + newArg.append(last, c - last); + // Skip over the escape character + last = c = next; } } break; case '[': { ++squareNesting; - newArgVec.push_back(*c); } break; case ']': { --squareNesting; - newArgVec.push_back(*c); } break; case ';': { @@ -1100,31 +1088,28 @@ void cmSystemTools::ExpandListArgument(const std::string& arg, // brackets. if(squareNesting == 0) { - if ( newArgVec.size() || emptyArgs ) + newArg.append(last, c - last); + // Skip over the semicolon + last = c + 1; + if ( !newArg.empty() || emptyArgs ) { // Add the last argument if the string is not empty. - newArgVec.push_back(0); - newargs.push_back(&*newArgVec.begin()); - newArgVec.clear(); + newargs.push_back(newArg); + newArg = ""; } } - else - { - newArgVec.push_back(*c); - } } break; default: { // Just append this character. - newArgVec.push_back(*c); } break; } } - if ( newArgVec.size() || emptyArgs ) + newArg.append(last); + if ( !newArg.empty() || emptyArgs ) { // Add the last argument if the string is not empty. - newArgVec.push_back(0); - newargs.push_back(&*newArgVec.begin()); + newargs.push_back(newArg); } } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index db34bd8..1c2b27a 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -71,6 +71,12 @@ struct cmTarget::ImportInfo cmTarget::LinkInterface LinkInterface; }; +//---------------------------------------------------------------------------- +struct cmTarget::CompileInfo +{ + std::string CompilePdbDir; +}; + struct TargetConfigPair : public std::pair<cmTarget const* , std::string> { TargetConfigPair(cmTarget const* tgt, const std::string &config) : std::pair<cmTarget const* , std::string>(tgt, config) {} @@ -83,17 +89,12 @@ public: cmTargetInternals() { this->PolicyWarnedCMP0022 = false; - this->SourceFileFlagsConstructed = false; } cmTargetInternals(cmTargetInternals const&) { this->PolicyWarnedCMP0022 = false; - this->SourceFileFlagsConstructed = false; } ~cmTargetInternals(); - typedef cmTarget::SourceFileFlags SourceFileFlags; - mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap; - mutable bool SourceFileFlagsConstructed; // The backtrace when the target was created. cmListFileBacktrace Backtrace; @@ -101,9 +102,17 @@ public: // Cache link interface computation from each configuration. struct OptionalLinkInterface: public cmTarget::LinkInterface { - OptionalLinkInterface(): Exists(false) {} + OptionalLinkInterface(): + Exists(false), Complete(false), ExplicitLibraries(0) {} bool Exists; + bool Complete; + const char* ExplicitLibraries; }; + void ComputeLinkInterface(cmTarget const* thisTarget, + const char* config, OptionalLinkInterface& iface, + cmTarget const* head, + const char *explicitLibraries) const; + typedef std::map<TargetConfigPair, OptionalLinkInterface> LinkInterfaceMapType; LinkInterfaceMapType LinkInterfaceMap; @@ -116,6 +125,9 @@ public: ImportInfoMapType; ImportInfoMapType ImportInfoMap; + typedef std::map<std::string, cmTarget::CompileInfo> CompileInfoMapType; + CompileInfoMapType CompileInfoMap; + // Cache link implementation computation from each configuration. typedef std::map<TargetConfigPair, cmTarget::LinkImplementation> LinkImplMapType; @@ -267,6 +279,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", 0); + this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", 0); this->SetPropertyDefault("Fortran_FORMAT", 0); this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0); this->SetPropertyDefault("GNUtoMS", 0); @@ -295,6 +308,7 @@ void cmTarget::SetMakefile(cmMakefile* mf) "LIBRARY_OUTPUT_DIRECTORY_", "RUNTIME_OUTPUT_DIRECTORY_", "PDB_OUTPUT_DIRECTORY_", + "COMPILE_PDB_OUTPUT_DIRECTORY_", "MAP_IMPORTED_CONFIG_", 0}; for(std::vector<std::string>::iterator ci = configNames.begin(); @@ -527,10 +541,11 @@ bool cmTarget::IsBundleOnApple() const } //---------------------------------------------------------------------------- -bool cmTarget::FindSourceFiles() +void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const { + assert(this->GetType() != INTERFACE_LIBRARY); for(std::vector<cmSourceFile*>::const_iterator - si = this->SourceFiles.begin(); + si = this->SourceFiles.begin(); si != this->SourceFiles.end(); ++si) { std::string e; @@ -542,16 +557,9 @@ bool cmTarget::FindSourceFiles() cm->IssueMessage(cmake::FATAL_ERROR, e, this->GetBacktrace()); } - return false; + return; } } - return true; -} - -//---------------------------------------------------------------------------- -void cmTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const -{ - assert(this->GetType() != INTERFACE_LIBRARY); files = this->SourceFiles; } @@ -648,109 +656,6 @@ void cmTarget::ProcessSourceExpression(std::string const& expr) } //---------------------------------------------------------------------------- -struct cmTarget::SourceFileFlags -cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const -{ - struct SourceFileFlags flags; - this->ConstructSourceFileFlags(); - std::map<cmSourceFile const*, SourceFileFlags>::iterator si = - this->Internal->SourceFlagsMap.find(sf); - if(si != this->Internal->SourceFlagsMap.end()) - { - flags = si->second; - } - return flags; -} - -//---------------------------------------------------------------------------- -void cmTarget::ConstructSourceFileFlags() const -{ - if(this->Internal->SourceFileFlagsConstructed) - { - return; - } - this->Internal->SourceFileFlagsConstructed = true; - - // Process public headers to mark the source files. - if(const char* files = this->GetProperty("PUBLIC_HEADER")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::iterator it = relFiles.begin(); - it != relFiles.end(); ++it) - { - if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) - { - SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; - flags.MacFolder = "Headers"; - flags.Type = cmTarget::SourceFileTypePublicHeader; - } - } - } - - // Process private headers after public headers so that they take - // precedence if a file is listed in both. - if(const char* files = this->GetProperty("PRIVATE_HEADER")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::iterator it = relFiles.begin(); - it != relFiles.end(); ++it) - { - if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) - { - SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; - flags.MacFolder = "PrivateHeaders"; - flags.Type = cmTarget::SourceFileTypePrivateHeader; - } - } - } - - // Mark sources listed as resources. - if(const char* files = this->GetProperty("RESOURCE")) - { - std::vector<std::string> relFiles; - cmSystemTools::ExpandListArgument(files, relFiles); - for(std::vector<std::string>::iterator it = relFiles.begin(); - it != relFiles.end(); ++it) - { - if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str())) - { - SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; - flags.MacFolder = "Resources"; - flags.Type = cmTarget::SourceFileTypeResource; - } - } - } - - // Handle the MACOSX_PACKAGE_LOCATION property on source files that - // were not listed in one of the other lists. - std::vector<cmSourceFile*> sources; - this->GetSourceFiles(sources); - for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); - si != sources.end(); ++si) - { - cmSourceFile* sf = *si; - if(const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) - { - SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf]; - if(flags.Type == cmTarget::SourceFileTypeNormal) - { - flags.MacFolder = location; - if(strcmp(location, "Resources") == 0) - { - flags.Type = cmTarget::SourceFileTypeResource; - } - else - { - flags.Type = cmTarget::SourceFileTypeMacContent; - } - } - } - } -} - -//---------------------------------------------------------------------------- void cmTarget::MergeLinkLibraries( cmMakefile& mf, const char *selfname, const LinkLibraryVectorType& libs ) @@ -2467,7 +2372,7 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo(const char* config) const OutputInfo info; this->ComputeOutputDir(config, false, info.OutDir); this->ComputeOutputDir(config, true, info.ImpDir); - if(!this->ComputePDBOutputDir(config, info.PdbDir)) + if(!this->ComputePDBOutputDir("PDB", config, info.PdbDir)) { info.PdbDir = info.OutDir; } @@ -2478,6 +2383,45 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo(const char* config) const } //---------------------------------------------------------------------------- +cmTarget::CompileInfo const* cmTarget::GetCompileInfo(const char* config) const +{ + // There is no compile information for imported targets. + if(this->IsImported()) + { + return 0; + } + + if(this->GetType() > cmTarget::OBJECT_LIBRARY) + { + std::string msg = "cmTarget::GetCompileInfo called for "; + msg += this->GetName(); + msg += " which has type "; + msg += cmTarget::GetTargetTypeName(this->GetType()); + this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, msg); + abort(); + return 0; + } + + // Lookup/compute/cache the compile information for this configuration. + std::string config_upper; + if(config && *config) + { + config_upper = cmSystemTools::UpperCase(config); + } + typedef cmTargetInternals::CompileInfoMapType CompileInfoMapType; + CompileInfoMapType::const_iterator i = + this->Internal->CompileInfoMap.find(config_upper); + if(i == this->Internal->CompileInfoMap.end()) + { + CompileInfo info; + this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir); + CompileInfoMapType::value_type entry(config_upper, info); + i = this->Internal->CompileInfoMap.insert(entry).first; + } + return &i->second; +} + +//---------------------------------------------------------------------------- std::string cmTarget::GetDirectory(const char* config, bool implib) const { if (this->IsImported()) @@ -2507,6 +2451,16 @@ std::string cmTarget::GetPDBDirectory(const char* config) const } //---------------------------------------------------------------------------- +std::string cmTarget::GetCompilePDBDirectory(const char* config) const +{ + if(CompileInfo const* info = this->GetCompileInfo(config)) + { + return info->CompilePdbDir; + } + return ""; +} + +//---------------------------------------------------------------------------- const char* cmTarget::GetLocation(const char* config) const { if (this->IsImported()) @@ -3167,6 +3121,49 @@ std::string cmTarget::GetPDBName(const char* config) const } //---------------------------------------------------------------------------- +std::string cmTarget::GetCompilePDBName(const char* config) const +{ + std::string prefix; + std::string base; + std::string suffix; + this->GetFullNameInternal(config, false, prefix, base, suffix); + + // Check for a per-configuration output directory target property. + std::string configUpper = cmSystemTools::UpperCase(config? config : ""); + std::string configProp = "COMPILE_PDB_NAME_"; + configProp += configUpper; + const char* config_name = this->GetProperty(configProp.c_str()); + if(config_name && *config_name) + { + return prefix + config_name + ".pdb"; + } + + const char* name = this->GetProperty("COMPILE_PDB_NAME"); + if(name && *name) + { + return prefix + name + ".pdb"; + } + + return ""; +} + +//---------------------------------------------------------------------------- +std::string cmTarget::GetCompilePDBPath(const char* config) const +{ + std::string dir = this->GetCompilePDBDirectory(config); + std::string name = this->GetCompilePDBName(config); + if(dir.empty() && !name.empty()) + { + dir = this->GetPDBDirectory(config); + } + if(!dir.empty()) + { + dir += "/"; + } + return dir + name; +} + +//---------------------------------------------------------------------------- bool cmTarget::HasSOName(const char* config) const { // soname is supported only for shared libraries and modules, @@ -4111,13 +4108,13 @@ bool cmTarget::ComputeOutputDir(const char* config, } //---------------------------------------------------------------------------- -bool cmTarget::ComputePDBOutputDir(const char* config, std::string& out) const +bool cmTarget::ComputePDBOutputDir(const char* kind, const char* config, + std::string& out) const { // Look for a target property defining the target output directory // based on the target type. - std::string targetTypeName = "PDB"; const char* propertyName = 0; - std::string propertyNameStr = targetTypeName; + std::string propertyNameStr = kind; if(!propertyNameStr.empty()) { propertyNameStr += "_OUTPUT_DIRECTORY"; @@ -4127,7 +4124,7 @@ bool cmTarget::ComputePDBOutputDir(const char* config, std::string& out) const // Check for a per-configuration output directory target property. std::string configUpper = cmSystemTools::UpperCase(config? config : ""); const char* configProp = 0; - std::string configPropStr = targetTypeName; + std::string configPropStr = kind; if(!configPropStr.empty()) { configPropStr += "_OUTPUT_DIRECTORY_"; @@ -4530,12 +4527,13 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet)); - cmComputeLinkInformation *info = tgt->GetLinkInformation(config); - if(!info) + std::vector<cmTarget*> deps; + tgt->GetTransitiveTargetClosure(config, tgt, deps); + + if(deps.empty()) { return propContent; } - const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); bool propInitialized = explicitlySet; std::string report = " * Target \""; @@ -4555,7 +4553,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, report += "\" property not set.\n"; } - for(cmComputeLinkInformation::ItemVector::const_iterator li = + for(std::vector<cmTarget*>::const_iterator li = deps.begin(); li != deps.end(); ++li) { @@ -4565,23 +4563,20 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, // target itself has a POSITION_INDEPENDENT_CODE which disagrees // with a dependency. - if (!li->Target) - { - continue; - } + cmTarget const* theTarget = *li; - const bool ifaceIsSet = li->Target->GetProperties() + const bool ifaceIsSet = theTarget->GetProperties() .find("INTERFACE_" + p) - != li->Target->GetProperties().end(); + != theTarget->GetProperties().end(); PropertyType ifacePropContent = - getTypedProperty<PropertyType>(li->Target, + getTypedProperty<PropertyType>(theTarget, ("INTERFACE_" + p).c_str(), 0); std::string reportEntry; if (ifaceIsSet) { reportEntry += " * Target \""; - reportEntry += li->Target->GetName(); + reportEntry += theTarget->GetName(); reportEntry += "\" property value \""; reportEntry += valueAsString<PropertyType>(ifacePropContent); reportEntry += "\" "; @@ -4602,7 +4597,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, e << "Property " << p << " on target \"" << tgt->GetName() << "\" does\nnot match the " "INTERFACE_" << p << " property requirement\nof " - "dependency \"" << li->Target->GetName() << "\".\n"; + "dependency \"" << theTarget->GetName() << "\".\n"; cmSystemTools::Error(e.str().c_str()); break; } @@ -4636,7 +4631,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, << tgt->GetName() << "\" is\nimplied to be " << defaultValue << " because it was used to determine the link libraries\n" "already. The INTERFACE_" << p << " property on\ndependency \"" - << li->Target->GetName() << "\" is in conflict.\n"; + << theTarget->GetName() << "\" is in conflict.\n"; cmSystemTools::Error(e.str().c_str()); break; } @@ -4667,7 +4662,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, { cmOStringStream e; e << "The INTERFACE_" << p << " property of \"" - << li->Target->GetName() << "\" does\nnot agree with the value " + << theTarget->GetName() << "\" does\nnot agree with the value " "of " << p << " already determined\nfor \"" << tgt->GetName() << "\".\n"; cmSystemTools::Error(e.str().c_str()); @@ -4748,23 +4743,19 @@ bool isLinkDependentProperty(cmTarget const* tgt, const std::string &p, const char *interfaceProperty, const char *config) { - cmComputeLinkInformation *info = tgt->GetLinkInformation(config); - if(!info) + std::vector<cmTarget*> deps; + tgt->GetTransitiveTargetClosure(config, tgt, deps); + + if(deps.empty()) { return false; } - const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); - - for(cmComputeLinkInformation::ItemVector::const_iterator li = + for(std::vector<cmTarget*>::const_iterator li = deps.begin(); li != deps.end(); ++li) { - if (!li->Target) - { - continue; - } - const char *prop = li->Target->GetProperty(interfaceProperty); + const char *prop = (*li)->GetProperty(interfaceProperty); if (!prop) { continue; @@ -5316,24 +5307,124 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config, { // Compute the link interface for this configuration. cmTargetInternals::OptionalLinkInterface iface; - iface.Exists = this->ComputeLinkInterface(config, iface, head); + iface.ExplicitLibraries = + this->ComputeLinkInterfaceLibraries(config, iface, head, iface.Exists); + if (iface.Exists) + { + this->Internal->ComputeLinkInterface(this, config, iface, + head, iface.ExplicitLibraries); + } // Store the information for this configuration. cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); i = this->Internal->LinkInterfaceMap.insert(entry).first; } + else if(!i->second.Complete && i->second.Exists) + { + this->Internal->ComputeLinkInterface(this, config, i->second, head, + i->second.ExplicitLibraries); + } - return i->second.Exists? &i->second : 0; + return i->second.Exists ? &i->second : 0; } //---------------------------------------------------------------------------- -void cmTarget::GetTransitivePropertyLinkLibraries( - const char* config, +cmTarget::LinkInterface const* +cmTarget::GetLinkInterfaceLibraries(const char* config, + cmTarget const* head) const +{ + // Imported targets have their own link interface. + if(this->IsImported()) + { + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head)) + { + return &info->LinkInterface; + } + return 0; + } + + // Link interfaces are not supported for executables that do not + // export symbols. + if(this->GetType() == cmTarget::EXECUTABLE && + !this->IsExecutableWithExports()) + { + return 0; + } + + // Lookup any existing link interface for this configuration. + TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : "")); + + cmTargetInternals::LinkInterfaceMapType::iterator + i = this->Internal->LinkInterfaceMap.find(key); + if(i == this->Internal->LinkInterfaceMap.end()) + { + // Compute the link interface for this configuration. + cmTargetInternals::OptionalLinkInterface iface; + iface.ExplicitLibraries = this->ComputeLinkInterfaceLibraries(config, + iface, + head, + iface.Exists); + + // Store the information for this configuration. + cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); + i = this->Internal->LinkInterfaceMap.insert(entry).first; + } + + return i->second.Exists ? &i->second : 0; +} + +//---------------------------------------------------------------------------- +void processILibs(const char* config, + cmTarget const* headTarget, + std::string const& name, + std::vector<cmTarget*>& tgts, std::set<cmTarget*>& emitted) +{ + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(name.c_str())) + { + if (emitted.insert(tgt).second) + { + tgts.push_back(tgt); + std::vector<std::string> ilibs; + cmTarget::LinkInterface const* iface = + tgt->GetLinkInterfaceLibraries(config, headTarget); + if (iface) + { + for(std::vector<std::string>::const_iterator + it = iface->Libraries.begin(); + it != iface->Libraries.end(); ++it) + { + processILibs(config, headTarget, *it, tgts, emitted); + } + } + } + } +} + +//---------------------------------------------------------------------------- +void cmTarget::GetTransitiveTargetClosure(const char* config, cmTarget const* headTarget, - std::vector<std::string> &libs) const + std::vector<cmTarget*> &tgts) const { - cmTarget::LinkInterface const* iface = this->GetLinkInterface(config, - headTarget); + std::set<cmTarget*> emitted; + + cmTarget::LinkImplementation const* impl + = this->GetLinkImplementationLibraries(config, headTarget); + + for(std::vector<std::string>::const_iterator it = impl->Libraries.begin(); + it != impl->Libraries.end(); ++it) + { + processILibs(config, headTarget, *it, tgts, emitted); + } +} + +//---------------------------------------------------------------------------- +void cmTarget::GetTransitivePropertyTargets(const char* config, + cmTarget const* headTarget, + std::vector<cmTarget*> &tgts) const +{ + cmTarget::LinkInterface const* iface + = this->GetLinkInterfaceLibraries(config, headTarget); if (!iface) { return; @@ -5342,7 +5433,15 @@ void cmTarget::GetTransitivePropertyLinkLibraries( || this->GetPolicyStatusCMP0022() == cmPolicies::WARN || this->GetPolicyStatusCMP0022() == cmPolicies::OLD) { - libs = iface->Libraries; + for(std::vector<std::string>::const_iterator it = iface->Libraries.begin(); + it != iface->Libraries.end(); ++it) + { + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(it->c_str())) + { + tgts.push_back(tgt); + } + } return; } @@ -5360,17 +5459,30 @@ void cmTarget::GetTransitivePropertyLinkLibraries( cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(), linkIfaceProp, 0, 0); dagChecker.SetTransitivePropertiesOnly(); + std::vector<std::string> libs; cmSystemTools::ExpandListArgument(ge.Parse(interfaceLibs)->Evaluate( this->Makefile, config, false, headTarget, this, &dagChecker), libs); + + for(std::vector<std::string>::const_iterator it = libs.begin(); + it != libs.end(); ++it) + { + if (cmTarget* tgt = headTarget->GetMakefile() + ->FindTargetToUse(it->c_str())) + { + tgts.push_back(tgt); + } + } } //---------------------------------------------------------------------------- -bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, - cmTarget const* headTarget) const +const char* cmTarget::ComputeLinkInterfaceLibraries(const char* config, + LinkInterface& iface, + cmTarget const* headTarget, + bool &exists) const { // Construct the property name suffix for this configuration. std::string suffix = "_"; @@ -5446,8 +5558,10 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, (this->GetType() == cmTarget::EXECUTABLE || (this->GetType() == cmTarget::MODULE_LIBRARY))) { - return false; + exists = false; + return 0; } + exists = true; if(explicitLibraries) { @@ -5462,52 +5576,6 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, false, headTarget, this, &dagChecker), iface.Libraries); - - if(this->GetType() == cmTarget::SHARED_LIBRARY - || this->GetType() == cmTarget::STATIC_LIBRARY - || this->GetType() == cmTarget::INTERFACE_LIBRARY) - { - // Shared libraries may have runtime implementation dependencies - // on other shared libraries that are not in the interface. - std::set<cmStdString> emitted; - for(std::vector<std::string>::const_iterator - li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) - { - emitted.insert(*li); - } - if (this->GetType() != cmTarget::INTERFACE_LIBRARY) - { - LinkImplementation const* impl = this->GetLinkImplementation(config, - headTarget); - for(std::vector<std::string>::const_iterator - li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) - { - if(emitted.insert(*li).second) - { - if(cmTarget* tgt = this->Makefile->FindTargetToUse(*li)) - { - // This is a runtime dependency on another shared library. - if(tgt->GetType() == cmTarget::SHARED_LIBRARY) - { - iface.SharedDeps.push_back(*li); - } - } - else - { - // TODO: Recognize shared library file names. Perhaps this - // should be moved to cmComputeLinkInformation, but that creates - // a chicken-and-egg problem since this list is needed for its - // construction. - } - } - } - if(this->LinkLanguagePropagatesToDependents()) - { - // Targets using this archive need its language runtime libraries. - iface.Languages = impl->Languages; - } - } - } } else if (this->PolicyStatusCMP0022 == cmPolicies::WARN || this->PolicyStatusCMP0022 == cmPolicies::OLD) @@ -5517,17 +5585,9 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, // to the link implementation. { // The link implementation is the default link interface. - LinkImplementation const* impl = this->GetLinkImplementation(config, - headTarget); - iface.ImplementationIsInterface = true; + LinkImplementation const* impl = + this->GetLinkImplementationLibraries(config, headTarget); iface.Libraries = impl->Libraries; - iface.WrongConfigLibraries = impl->WrongConfigLibraries; - if(this->LinkLanguagePropagatesToDependents()) - { - // Targets using this archive need its language runtime libraries. - iface.Languages = impl->Languages; - } - if(this->PolicyStatusCMP0022 == cmPolicies::WARN && !this->Internal->PolicyWarnedCMP0022) { @@ -5592,25 +5652,107 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, } } } + return explicitLibraries; +} - if(this->GetType() == cmTarget::STATIC_LIBRARY) +//---------------------------------------------------------------------------- +void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, + const char* config, + OptionalLinkInterface& iface, + cmTarget const* headTarget, + const char* explicitLibraries) const +{ + if(explicitLibraries) { + if(thisTarget->GetType() == cmTarget::SHARED_LIBRARY + || thisTarget->GetType() == cmTarget::STATIC_LIBRARY + || thisTarget->GetType() == cmTarget::INTERFACE_LIBRARY) + { + // Shared libraries may have runtime implementation dependencies + // on other shared libraries that are not in the interface. + std::set<cmStdString> emitted; + for(std::vector<std::string>::const_iterator + li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) + { + emitted.insert(*li); + } + if (thisTarget->GetType() != cmTarget::INTERFACE_LIBRARY) + { + cmTarget::LinkImplementation const* impl = + thisTarget->GetLinkImplementation(config, headTarget); + for(std::vector<std::string>::const_iterator + li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) + { + if(emitted.insert(*li).second) + { + if(cmTarget* tgt = thisTarget->Makefile->FindTargetToUse(*li)) + { + // This is a runtime dependency on another shared library. + if(tgt->GetType() == cmTarget::SHARED_LIBRARY) + { + iface.SharedDeps.push_back(*li); + } + } + else + { + // TODO: Recognize shared library file names. Perhaps this + // should be moved to cmComputeLinkInformation, but that creates + // a chicken-and-egg problem since this list is needed for its + // construction. + } + } + } + if(thisTarget->LinkLanguagePropagatesToDependents()) + { + // Targets using this archive need its language runtime libraries. + iface.Languages = impl->Languages; + } + } + } + } + else if (thisTarget->PolicyStatusCMP0022 == cmPolicies::WARN + || thisTarget->PolicyStatusCMP0022 == cmPolicies::OLD) + { + // The link implementation is the default link interface. + cmTarget::LinkImplementation const* + impl = thisTarget->GetLinkImplementation(config, headTarget); + iface.ImplementationIsInterface = true; + iface.WrongConfigLibraries = impl->WrongConfigLibraries; + if(thisTarget->LinkLanguagePropagatesToDependents()) + { + // Targets using this archive need its language runtime libraries. + iface.Languages = impl->Languages; + } + } + + if(thisTarget->GetType() == cmTarget::STATIC_LIBRARY) + { + // Construct the property name suffix for this configuration. + std::string suffix = "_"; + if(config && *config) + { + suffix += cmSystemTools::UpperCase(config); + } + else + { + suffix += "NOCONFIG"; + } + // How many repetitions are needed if this library has cyclic // dependencies? std::string propName = "LINK_INTERFACE_MULTIPLICITY"; propName += suffix; - if(const char* config_reps = this->GetProperty(propName.c_str())) + if(const char* config_reps = thisTarget->GetProperty(propName.c_str())) { sscanf(config_reps, "%u", &iface.Multiplicity); } else if(const char* reps = - this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) + thisTarget->GetProperty("LINK_INTERFACE_MULTIPLICITY")) { sscanf(reps, "%u", &iface.Multiplicity); } } - - return true; + iface.Complete = true; } //---------------------------------------------------------------------------- @@ -5633,6 +5775,41 @@ cmTarget::GetLinkImplementation(const char* config, cmTarget const* head) const // Compute the link implementation for this configuration. LinkImplementation impl; this->ComputeLinkImplementation(config, impl, head); + this->ComputeLinkImplementationLanguages(impl); + + // Store the information for this configuration. + cmTargetInternals::LinkImplMapType::value_type entry(key, impl); + i = this->Internal->LinkImplMap.insert(entry).first; + } + else if (i->second.Languages.empty()) + { + this->ComputeLinkImplementationLanguages(i->second); + } + + return &i->second; +} + +//---------------------------------------------------------------------------- +cmTarget::LinkImplementation const* +cmTarget::GetLinkImplementationLibraries(const char* config, + cmTarget const* head) const +{ + // There is no link implementation for imported targets. + if(this->IsImported()) + { + return 0; + } + + // Lookup any existing link implementation for this configuration. + TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : "")); + + cmTargetInternals::LinkImplMapType::iterator + i = this->Internal->LinkImplMap.find(key); + if(i == this->Internal->LinkImplMap.end()) + { + // Compute the link implementation for this configuration. + LinkImplementation impl; + this->ComputeLinkImplementation(config, impl, head); // Store the information for this configuration. cmTargetInternals::LinkImplMapType::value_type entry(key, impl); @@ -5715,7 +5892,12 @@ void cmTarget::ComputeLinkImplementation(const char* config, impl.WrongConfigLibraries.push_back(item); } } +} +//---------------------------------------------------------------------------- +void +cmTarget::ComputeLinkImplementationLanguages(LinkImplementation& impl) const +{ // This target needs runtime libraries for its source languages. std::set<cmStdString> languages; // Get languages used in our source files. diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 271824b..471ea94 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -140,34 +140,6 @@ public: } /** - * Flags for a given source file as used in this target. Typically assigned - * via SET_TARGET_PROPERTIES when the property is a list of source files. - */ - enum SourceFileType - { - SourceFileTypeNormal, - SourceFileTypePrivateHeader, // is in "PRIVATE_HEADER" target property - SourceFileTypePublicHeader, // is in "PUBLIC_HEADER" target property - SourceFileTypeResource, // is in "RESOURCE" target property *or* - // has MACOSX_PACKAGE_LOCATION=="Resources" - SourceFileTypeMacContent // has MACOSX_PACKAGE_LOCATION!="Resources" - }; - struct SourceFileFlags - { - SourceFileFlags(): Type(SourceFileTypeNormal), MacFolder(0) {} - SourceFileFlags(SourceFileFlags const& r): - Type(r.Type), MacFolder(r.MacFolder) {} - SourceFileType Type; - const char* MacFolder; // location inside Mac content folders - }; - - /** - * Get the flags for a given source file as used in this target - */ - struct SourceFileFlags - GetTargetSourceFileFlags(const cmSourceFile* sf) const; - - /** * Add sources to the target. */ void AddSources(std::vector<std::string> const& srcs); @@ -292,9 +264,14 @@ public: if the target cannot be linked. */ LinkInterface const* GetLinkInterface(const char* config, cmTarget const* headTarget) const; - void GetTransitivePropertyLinkLibraries(const char* config, + LinkInterface const* GetLinkInterfaceLibraries(const char* config, + cmTarget const* headTarget) const; + void GetTransitivePropertyTargets(const char* config, + cmTarget const* headTarget, + std::vector<cmTarget*> &libs) const; + void GetTransitiveTargetClosure(const char* config, cmTarget const* headTarget, - std::vector<std::string> &libs) const; + std::vector<cmTarget*> &libs) const; /** The link implementation specifies the direct library dependencies needed by the object files of the target. */ @@ -313,6 +290,9 @@ public: LinkImplementation const* GetLinkImplementation(const char* config, cmTarget const* head) const; + LinkImplementation const* GetLinkImplementationLibraries(const char* config, + cmTarget const* head) const; + /** Link information from the transitive closure of the link implementation and the interfaces of its dependencies. */ struct LinkClosure @@ -340,7 +320,13 @@ public: If the configuration name is given then the generator will add its subdirectory for that configuration. Otherwise just the canonical pdb output directory is given. */ - std::string GetPDBDirectory(const char* config = 0) const; + std::string GetPDBDirectory(const char* config) const; + + /** Get the directory in which to place the target compiler .pdb file. + If the configuration name is given then the generator will add its + subdirectory for that configuration. Otherwise just the canonical + compiler pdb output directory is given. */ + std::string GetCompilePDBDirectory(const char* config = 0) const; /** Get the location of the target in the build tree for the given configuration. This location is suitable for use as the LOCATION @@ -358,11 +344,6 @@ public: void GetTargetVersion(bool soversion, int& major, int& minor, int& patch) const; - /** - * Make sure the full path to all source files is known. - */ - bool FindSourceFiles(); - ///! Return the preferred linker language for this target const char* GetLinkerLanguage(const char* config = 0, cmTarget const* head = 0) const; @@ -375,7 +356,13 @@ public: const char* config=0, bool implib = false) const; /** Get the name of the pdb file for the target. */ - std::string GetPDBName(const char* config=0) const; + std::string GetPDBName(const char* config) const; + + /** Get the name of the compiler pdb file for the target. */ + std::string GetCompilePDBName(const char* config=0) const; + + /** Get the path for the MSVC /Fd option for this target. */ + std::string GetCompilePDBPath(const char* config=0) const; /** Whether this library has soname enabled and platform supports it. */ bool HasSOName(const char* config) const; @@ -710,7 +697,8 @@ private: OutputInfo const* GetOutputInfo(const char* config) const; bool ComputeOutputDir(const char* config, bool implib, std::string& out) const; - bool ComputePDBOutputDir(const char* config, std::string& out) const; + bool ComputePDBOutputDir(const char* kind, const char* config, + std::string& out) const; // Cache import information from properties for each configuration. struct ImportInfo; @@ -719,16 +707,23 @@ private: void ComputeImportInfo(std::string const& desired_config, ImportInfo& info, cmTarget const* head) const; + // Cache target compile paths for each configuration. + struct CompileInfo; + CompileInfo const* GetCompileInfo(const char* config) const; + mutable cmTargetLinkInformationMap LinkInformation; void CheckPropertyCompatibility(cmComputeLinkInformation *info, const char* config) const; - bool ComputeLinkInterface(const char* config, LinkInterface& iface, - cmTarget const* head) const; + const char* ComputeLinkInterfaceLibraries(const char* config, + LinkInterface& iface, + cmTarget const* head, + bool &exists) const; void ComputeLinkImplementation(const char* config, LinkImplementation& impl, cmTarget const* head) const; + void ComputeLinkImplementationLanguages(LinkImplementation& impl) const; void ComputeLinkClosure(const char* config, LinkClosure& lc, cmTarget const* head) const; @@ -756,7 +751,6 @@ private: friend class cmTargetTraceDependencies; cmTargetInternalPointer Internal; - void ConstructSourceFileFlags() const; void ComputeVersionedName(std::string& vName, std::string const& prefix, std::string const& base, diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ed7e243..2d21a3d 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1427,6 +1427,17 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( clOptions.OutputPreprocessorDefinitions(*this->BuildFileStream, " ", "\n", "CXX"); this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3); + + // Specify the compiler program database file if configured. + std::string pdb = this->Target->GetCompilePDBPath(configName.c_str()); + if(!pdb.empty()) + { + this->ConvertToWindowsSlash(pdb); + this->WriteString("<ProgramDataBaseFileName>", 3); + *this->BuildFileStream << cmVS10EscapeXML(pdb) + << "</ProgramDataBaseFileName>\n"; + } + this->WriteString("</ClCompile>\n", 2); } @@ -1666,10 +1677,10 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) linkOptions.AddFlag("ImportLibrary", imLib.c_str()); linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str()); linkOptions.Parse(flags.c_str()); - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) + std::string def = this->GeneratorTarget->GetModuleDefinitionFile(); + if(!def.empty()) { - linkOptions.AddFlag("ModuleDefinitionFile", - this->GeneratorTarget->ModuleDefinitionFile.c_str()); + linkOptions.AddFlag("ModuleDefinitionFile", def.c_str()); } this->LinkOptions[config] = pOptions.release(); diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt index 9727930..a875f07 100644 --- a/Tests/BuildDepends/CMakeLists.txt +++ b/Tests/BuildDepends/CMakeLists.txt @@ -68,6 +68,8 @@ file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_exe.h "#define link_depends_no_shared_exe_value 0\n") set(link_depends_no_shared_check_txt ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_check.txt) +file(WRITE ${BuildDepends_BINARY_DIR}/Project/external.in "external original\n") + help_xcode_depends() message("Building project first time") @@ -166,6 +168,19 @@ else() "Targets link_depends_no_shared_lib and link_depends_no_shared_exe not both built.") endif() +if(EXISTS ${BuildDepends_BINARY_DIR}/Project/external.out) + file(STRINGS ${BuildDepends_BINARY_DIR}/Project/external.out external_out) + if("${external_out}" STREQUAL "external original") + message(STATUS "external.out contains '${external_out}'") + else() + message(SEND_ERROR "Project did not initially build properly: " + "external.out contains '${external_out}'") + endif() +else() + message(SEND_ERROR "Project did not initially build properly: " + "external.out is missing") +endif() + message("Waiting 3 seconds...") # any additional argument will cause ${bar} to wait forever execute_process(COMMAND ${bar} -infinite TIMEOUT 3 OUTPUT_VARIABLE out) @@ -191,6 +206,8 @@ if(TEST_LINK_DEPENDS) file(WRITE ${TEST_LINK_DEPENDS} "2") endif() +file(WRITE ${BuildDepends_BINARY_DIR}/Project/external.in "external changed\n") + help_xcode_depends() message("Building project second time") @@ -294,3 +311,16 @@ else() message(SEND_ERROR "Project did not rebuild properly. " "Targets link_depends_no_shared_lib and link_depends_no_shared_exe not both built.") endif() + +if(EXISTS ${BuildDepends_BINARY_DIR}/Project/external.out) + file(STRINGS ${BuildDepends_BINARY_DIR}/Project/external.out external_out) + if("${external_out}" STREQUAL "external changed") + message(STATUS "external.out contains '${external_out}'") + else() + message(SEND_ERROR "Project did not rebuild properly: " + "external.out contains '${external_out}'") + endif() +else() + message(SEND_ERROR "Project did not rebuild properly: " + "external.out is missing") +endif() diff --git a/Tests/BuildDepends/Project/CMakeLists.txt b/Tests/BuildDepends/Project/CMakeLists.txt index 8806ecd..9ee4a43 100644 --- a/Tests/BuildDepends/Project/CMakeLists.txt +++ b/Tests/BuildDepends/Project/CMakeLists.txt @@ -139,3 +139,15 @@ add_custom_target(header_tgt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dir/header.h) include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_executable(ninjadep ninjadep.cpp) add_dependencies(ninjadep header_tgt) + +include(ExternalProject) +ExternalProject_Add(ExternalBuild + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/External + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/External + STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/External/Stamp + BUILD_ALWAYS 1 + CMAKE_ARGS + -Dexternal_in=${CMAKE_CURRENT_BINARY_DIR}/external.in + -Dexternal_out=${CMAKE_CURRENT_BINARY_DIR}/external.out + INSTALL_COMMAND "" + ) diff --git a/Tests/BuildDepends/Project/External/CMakeLists.txt b/Tests/BuildDepends/Project/External/CMakeLists.txt new file mode 100644 index 0000000..c6015b6 --- /dev/null +++ b/Tests/BuildDepends/Project/External/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0) +project(BuildDependsExternal NONE) +if(NOT DEFINED external_in) + message(FATAL_ERROR "Define external_in") +endif() +if(NOT DEFINED external_out) + message(FATAL_ERROR "Define external_out") +endif() +add_custom_command( + OUTPUT ${external_out} + COMMAND ${CMAKE_COMMAND} -E copy ${external_in} ${external_out} + DEPENDS ${external_in} + ) +add_custom_target(drive ALL DEPENDS ${external_out}) diff --git a/Tests/PDBDirectoryAndName/CMakeLists.txt b/Tests/PDBDirectoryAndName/CMakeLists.txt index 28e46b1..90af600 100644 --- a/Tests/PDBDirectoryAndName/CMakeLists.txt +++ b/Tests/PDBDirectoryAndName/CMakeLists.txt @@ -6,6 +6,13 @@ if(NOT MSVC AND NOT "${CMAKE_C_COMPILER_ID}" MATCHES "^(Intel)$") message(FATAL_ERROR "The PDBDirectoryAndName test works only with MSVC or Intel") endif() +# Intel 11.1 does not support /Fd but Intel 14.0 does. +# TODO: Did a version in between these add it? +if(CMAKE_C_COMPILER_ID STREQUAL Intel AND + CMAKE_C_COMPILER_VERSION VERSION_LESS 14.0) + set(NO_COMPILE_PDB 1) +endif() + set(my_targets "") add_library(mylibA SHARED mylibA.c) @@ -17,12 +24,12 @@ list(APPEND my_targets mylibA) add_library(mylibB STATIC mylibB.c) set_target_properties(mylibB PROPERTIES - PDB_NAME "mylibB_Special" - PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mylibB_PDB" + COMPILE_PDB_NAME "mylibB_Special" + COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mylibB_PDB" ) -# TODO: The only .pdb available for a static library is that generated -# by the compiler /Fd option which is not the same as the linker /pdb. -# list(APPEND my_targets mylibB) +if(NOT NO_COMPILE_PDB) + list(APPEND my_targets mylibB) +endif() add_library(mylibC SHARED mylibC.c) set_target_properties(mylibC PROPERTIES @@ -32,10 +39,11 @@ list(APPEND my_targets mylibC) add_library(mylibD STATIC mylibD.c) set_target_properties(mylibD PROPERTIES - PDB_NAME "mylibD_Special" + COMPILE_PDB_NAME "mylibD_Special" ) -# TODO: See comment for mylibB. -# list(APPEND my_targets mylibD) +if(NOT NO_COMPILE_PDB) + list(APPEND my_targets mylibD) +endif() add_executable(myexe myexe.c) set_target_properties(myexe PROPERTIES @@ -66,6 +74,12 @@ set(pdbs "") foreach(t ${my_targets}) get_property(pdb_name TARGET ${t} PROPERTY PDB_NAME) get_property(pdb_dir TARGET ${t} PROPERTY PDB_OUTPUT_DIRECTORY) + if(NOT pdb_name) + get_property(pdb_name TARGET ${t} PROPERTY COMPILE_PDB_NAME) + endif() + if(NOT pdb_dir) + get_property(pdb_dir TARGET ${t} PROPERTY COMPILE_PDB_OUTPUT_DIRECTORY) + endif() if(NOT pdb_dir) set(pdb_dir ${CMAKE_CURRENT_BINARY_DIR}) endif() diff --git a/Tests/RunCMake/CompatibleInterface/DebugProperties-stderr.txt b/Tests/RunCMake/CompatibleInterface/DebugProperties-stderr.txt index 17b8a5c..82a34d5 100644 --- a/Tests/RunCMake/CompatibleInterface/DebugProperties-stderr.txt +++ b/Tests/RunCMake/CompatibleInterface/DebugProperties-stderr.txt @@ -1,4 +1,11 @@ CMake Debug Log: + Boolean compatibility of property "BOOL_PROP7" for target + "CompatibleInterface" \(result: "FALSE"\): + + \* Target "CompatibleInterface" property is implied by use. + \* Target "iface1" property value "FALSE" \(Agree\) ++ +CMake Debug Log: Boolean compatibility of property "BOOL_PROP1" for target "CompatibleInterface" \(result: "TRUE"\): @@ -40,13 +47,6 @@ CMake Debug Log: \* Target "iface2" property value "FALSE" \(Agree\) + CMake Debug Log: - Boolean compatibility of property "BOOL_PROP7" for target - "CompatibleInterface" \(result: "FALSE"\): - - \* Target "CompatibleInterface" property is implied by use. - \* Target "iface1" property value "FALSE" \(Agree\) -+ -CMake Debug Log: String compatibility of property "STRING_PROP1" for target "CompatibleInterface" \(result: "prop1"\): diff --git a/Tests/RunCMake/Syntax/AtWithVariable-stderr.txt b/Tests/RunCMake/Syntax/AtWithVariable-stderr.txt new file mode 100644 index 0000000..5dcd4d7 --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariable-stderr.txt @@ -0,0 +1 @@ +-->wrong<-- diff --git a/Tests/RunCMake/Syntax/AtWithVariable.cmake b/Tests/RunCMake/Syntax/AtWithVariable.cmake new file mode 100644 index 0000000..2bbf61d --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariable.cmake @@ -0,0 +1,9 @@ +set(right "wrong") +set(var "\${right}") +# Expanded here. +set(ref "@var@") + +# 'right' is dereferenced because 'var' was dereferenced when +# assigning to 'ref' above. +string(CONFIGURE "${ref}" output) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/AtWithVariableAtOnly-stderr.txt b/Tests/RunCMake/Syntax/AtWithVariableAtOnly-stderr.txt new file mode 100644 index 0000000..cbd1be4 --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableAtOnly-stderr.txt @@ -0,0 +1 @@ +-->\${right}<-- diff --git a/Tests/RunCMake/Syntax/AtWithVariableAtOnly.cmake b/Tests/RunCMake/Syntax/AtWithVariableAtOnly.cmake new file mode 100644 index 0000000..e06484c --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableAtOnly.cmake @@ -0,0 +1,8 @@ +set(right "wrong") +set(var "\${right}") +# Expanded here. +set(ref "@var@") + +# No dereference done at all. +string(CONFIGURE "${ref}" output @ONLY) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/AtWithVariableAtOnlyFile-stderr.txt b/Tests/RunCMake/Syntax/AtWithVariableAtOnlyFile-stderr.txt new file mode 100644 index 0000000..90bffb6 --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableAtOnlyFile-stderr.txt @@ -0,0 +1,5 @@ +-->==>\${right}<== +==><== +==>\${var}<== +==>\${empty}<== +<-- diff --git a/Tests/RunCMake/Syntax/AtWithVariableAtOnlyFile.cmake b/Tests/RunCMake/Syntax/AtWithVariableAtOnlyFile.cmake new file mode 100644 index 0000000..bdd7bcd --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableAtOnlyFile.cmake @@ -0,0 +1,9 @@ +set(right "wrong") +set(var "\${right}") + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/atfile.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/atfile.txt" + @ONLY) +file(READ "${CMAKE_CURRENT_BINARY_DIR}/atfile.txt" output) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansion-stderr.txt b/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansion-stderr.txt new file mode 100644 index 0000000..cbd1be4 --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansion-stderr.txt @@ -0,0 +1 @@ +-->\${right}<-- diff --git a/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansion.cmake b/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansion.cmake new file mode 100644 index 0000000..840c7f0 --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansion.cmake @@ -0,0 +1,8 @@ +# Literal since 'var' is not defined. +set(ref "@var@") +set(right "wrong") +set(var "\${right}") + +# 'var' is dereferenced here. +string(CONFIGURE "${ref}" output) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansionAtOnly-stderr.txt b/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansionAtOnly-stderr.txt new file mode 100644 index 0000000..cbd1be4 --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansionAtOnly-stderr.txt @@ -0,0 +1 @@ +-->\${right}<-- diff --git a/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansionAtOnly.cmake b/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansionAtOnly.cmake new file mode 100644 index 0000000..b657506 --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableEmptyExpansionAtOnly.cmake @@ -0,0 +1,8 @@ +# Literal since 'var' is not defined. +set(ref "@var@") +set(right "wrong") +set(var "\${right}") + +# 'var' is dereferenced, but now 'right' +string(CONFIGURE "${ref}" output @ONLY) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/AtWithVariableFile-stderr.txt b/Tests/RunCMake/Syntax/AtWithVariableFile-stderr.txt new file mode 100644 index 0000000..43f029f --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableFile-stderr.txt @@ -0,0 +1,5 @@ +-->==>\${right}<== +==><== +==>\${right}<== +==><== +<-- diff --git a/Tests/RunCMake/Syntax/AtWithVariableFile.cmake b/Tests/RunCMake/Syntax/AtWithVariableFile.cmake new file mode 100644 index 0000000..c709099 --- /dev/null +++ b/Tests/RunCMake/Syntax/AtWithVariableFile.cmake @@ -0,0 +1,8 @@ +set(right "wrong") +set(var "\${right}") + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/atfile.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/atfile.txt") +file(READ "${CMAKE_CURRENT_BINARY_DIR}/atfile.txt" output) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/EscapeQuotes-stderr.txt b/Tests/RunCMake/Syntax/EscapeQuotes-stderr.txt new file mode 100644 index 0000000..077272d --- /dev/null +++ b/Tests/RunCMake/Syntax/EscapeQuotes-stderr.txt @@ -0,0 +1 @@ +-->"<-- diff --git a/Tests/RunCMake/Syntax/EscapeQuotes.cmake b/Tests/RunCMake/Syntax/EscapeQuotes.cmake new file mode 100644 index 0000000..46d2b6f --- /dev/null +++ b/Tests/RunCMake/Syntax/EscapeQuotes.cmake @@ -0,0 +1,9 @@ +set(var "\"") +set(ref "@var@") +set(rref "\${var}") + +string(CONFIGURE "${ref}" output ESCAPE_QUOTES) +message("-->${output}<--") + +string(CONFIGURE "${rref}" output ESCAPE_QUOTES) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/EscapedAt-stderr.txt b/Tests/RunCMake/Syntax/EscapedAt-stderr.txt new file mode 100644 index 0000000..a51c0d3 --- /dev/null +++ b/Tests/RunCMake/Syntax/EscapedAt-stderr.txt @@ -0,0 +1 @@ +-->\\n<-- diff --git a/Tests/RunCMake/Syntax/EscapedAt.cmake b/Tests/RunCMake/Syntax/EscapedAt.cmake new file mode 100644 index 0000000..1ced620 --- /dev/null +++ b/Tests/RunCMake/Syntax/EscapedAt.cmake @@ -0,0 +1,5 @@ +set(var "n") +set(ref "\\@var@") + +string(CONFIGURE "${ref}" output) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/ExpandInAt-stderr.txt b/Tests/RunCMake/Syntax/ExpandInAt-stderr.txt new file mode 100644 index 0000000..5da8b60 --- /dev/null +++ b/Tests/RunCMake/Syntax/ExpandInAt-stderr.txt @@ -0,0 +1 @@ +-->@foo@<-- diff --git a/Tests/RunCMake/Syntax/ExpandInAt.cmake b/Tests/RunCMake/Syntax/ExpandInAt.cmake new file mode 100644 index 0000000..98f0277 --- /dev/null +++ b/Tests/RunCMake/Syntax/ExpandInAt.cmake @@ -0,0 +1,6 @@ +set("\${varname}" bar) +set(var foo) +set(ref "@\${var}@") + +string(CONFIGURE "${ref}" output) +message("-->${output}<--") diff --git a/Tests/RunCMake/Syntax/ParenInENV-result.txt b/Tests/RunCMake/Syntax/ParenInENV-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/ParenInENV-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/ParenInENV-stderr.txt b/Tests/RunCMake/Syntax/ParenInENV-stderr.txt new file mode 100644 index 0000000..7ecfe11 --- /dev/null +++ b/Tests/RunCMake/Syntax/ParenInENV-stderr.txt @@ -0,0 +1,20 @@ +CMake Warning \(dev\) at CMakeLists.txt:3 \(include\): + Syntax Warning in cmake code at + + .*/Tests/RunCMake/Syntax/ParenInENV.cmake:2:21 + + Argument not separated from preceding token by whitespace. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error at ParenInENV.cmake:2 \(message\): + Syntax error in cmake code at + + .*/Tests/RunCMake/Syntax/ParenInENV.cmake:2 + + when parsing string + + -->\$ENV{e + + syntax error, unexpected \$end, expecting } \(9\) +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/Syntax/ParenInENV.cmake b/Tests/RunCMake/Syntax/ParenInENV.cmake new file mode 100644 index 0000000..148f726 --- /dev/null +++ b/Tests/RunCMake/Syntax/ParenInENV.cmake @@ -0,0 +1,2 @@ +set("ENV{e(x)}" value) +message(-->$ENV{e(x)}<--) diff --git a/Tests/RunCMake/Syntax/ParenInQuotedENV-stderr.txt b/Tests/RunCMake/Syntax/ParenInQuotedENV-stderr.txt new file mode 100644 index 0000000..7020c7e --- /dev/null +++ b/Tests/RunCMake/Syntax/ParenInQuotedENV-stderr.txt @@ -0,0 +1 @@ +-->value<-- diff --git a/Tests/RunCMake/Syntax/ParenInQuotedENV.cmake b/Tests/RunCMake/Syntax/ParenInQuotedENV.cmake new file mode 100644 index 0000000..6333717 --- /dev/null +++ b/Tests/RunCMake/Syntax/ParenInQuotedENV.cmake @@ -0,0 +1,2 @@ +set("ENV{e(x)}" value) +message("-->$ENV{e(x)}<--") diff --git a/Tests/RunCMake/Syntax/RunCMakeTest.cmake b/Tests/RunCMake/Syntax/RunCMakeTest.cmake index 5f05cfc..dcabd8a 100644 --- a/Tests/RunCMake/Syntax/RunCMakeTest.cmake +++ b/Tests/RunCMake/Syntax/RunCMakeTest.cmake @@ -52,3 +52,16 @@ run_cmake(UnterminatedString) run_cmake(UnterminatedBracket0) run_cmake(UnterminatedBracket1) run_cmake(UnterminatedBracketComment) + +# Variable expansion tests +run_cmake(ExpandInAt) +run_cmake(EscapedAt) +run_cmake(EscapeQuotes) +run_cmake(AtWithVariable) +run_cmake(AtWithVariableEmptyExpansion) +run_cmake(AtWithVariableAtOnly) +run_cmake(AtWithVariableEmptyExpansionAtOnly) +run_cmake(AtWithVariableFile) +run_cmake(AtWithVariableAtOnlyFile) +run_cmake(ParenInENV) +run_cmake(ParenInQuotedENV) diff --git a/Tests/RunCMake/Syntax/atfile.txt.in b/Tests/RunCMake/Syntax/atfile.txt.in new file mode 100644 index 0000000..3775919 --- /dev/null +++ b/Tests/RunCMake/Syntax/atfile.txt.in @@ -0,0 +1,4 @@ +==>@var@<== +==>@empty@<== +==>${var}<== +==>${empty}<== diff --git a/Utilities/Release/release_cmake.cmake b/Utilities/Release/release_cmake.cmake index 630f54f..a8772ee 100644 --- a/Utilities/Release/release_cmake.cmake +++ b/Utilities/Release/release_cmake.cmake @@ -67,14 +67,15 @@ macro(remote_command comment command) endmacro() if(CMAKE_DOC_TARBALL) - message("scp '${CMAKE_DOC_TARBALL}' '${HOST}:'") + get_filename_component(CMAKE_DOC_TARBALL_NAME "${CMAKE_DOC_TARBALL}" NAME) + string(REPLACE ".tar.gz" "-${SCRIPT_NAME}.tar.gz" CMAKE_DOC_TARBALL_STAGED "${CMAKE_DOC_TARBALL_NAME}") + message("scp '${CMAKE_DOC_TARBALL}' '${HOST}:${CMAKE_DOC_TARBALL_STAGED}'") execute_process(COMMAND - scp ${CMAKE_DOC_TARBALL} ${HOST}: + scp ${CMAKE_DOC_TARBALL} ${HOST}:${CMAKE_DOC_TARBALL_STAGED} RESULT_VARIABLE result) if(${result} GREATER 0) - message("error sending doc tarball with scp '${CMAKE_DOC_TARBALL}' '${HOST}:'") + message("error sending doc tarball with scp '${CMAKE_DOC_TARBALL}' '${HOST}:${CMAKE_DOC_TARBALL_STAGED}'") endif() - get_filename_component(CMAKE_DOC_TARBALL_NAME "${CMAKE_DOC_TARBALL}" NAME) endif() # set this so configure file will work from script mode diff --git a/Utilities/Release/release_cmake.sh.in b/Utilities/Release/release_cmake.sh.in index f41bda8..1f57c28 100755 --- a/Utilities/Release/release_cmake.sh.in +++ b/Utilities/Release/release_cmake.sh.in @@ -18,7 +18,7 @@ check_exit_value() CMAKE_DOC_TARBALL="" if [ ! -z "@CMAKE_DOC_TARBALL_NAME@" ] ; then CMAKE_DOC_TARBALL=@CMAKE_RELEASE_DIRECTORY@/@CMAKE_DOC_TARBALL_NAME@ - mv "$HOME/@CMAKE_DOC_TARBALL_NAME@" "$CMAKE_DOC_TARBALL" + mv "$HOME/@CMAKE_DOC_TARBALL_STAGED@" "$CMAKE_DOC_TARBALL" check_exit_value $? "mv doc tarball" || exit 1 fi diff --git a/Utilities/Release/upload_release.cmake b/Utilities/Release/upload_release.cmake index 9bf3523..0d928ba 100644 --- a/Utilities/Release/upload_release.cmake +++ b/Utilities/Release/upload_release.cmake @@ -3,7 +3,7 @@ if(NOT DEFINED PROJECT_PREFIX) set(PROJECT_PREFIX cmake-) endif() if(NOT VERSION) - set(VERSION 2.8) + set(VERSION 3.0) endif() set(dir "v${VERSION}") if("${VERSION}" MATCHES "master") |