diff options
26 files changed, 176 insertions, 29 deletions
diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake index 9d84f8d..187f408 100644 --- a/Modules/ExternalData.cmake +++ b/Modules/ExternalData.cmake @@ -156,7 +156,8 @@ # License text for the above reference.) function(ExternalData_add_test target) - ExternalData_expand_arguments("${target}" testArgs ${ARGN}) + # Expand all arguments as a single string to preserve escaped semicolons. + ExternalData_expand_arguments("${target}" testArgs "${ARGN}") add_test(${testArgs}) endfunction() @@ -234,13 +235,17 @@ endfunction() function(ExternalData_expand_arguments target outArgsVar) # Replace DATA{} references with real arguments. - set(data_regex "DATA{([^{}\r\n]*)}") + set(data_regex "DATA{([^;{}\r\n]*)}") set(other_regex "([^D]|D[^A]|DA[^T]|DAT[^A]|DATA[^{])+|.") set(outArgs "") + # This list expansion un-escapes semicolons in list element values so we + # must re-escape them below anywhere a new list expansion will occur. foreach(arg IN LISTS ARGN) if("x${arg}" MATCHES "${data_regex}") + # Re-escape in-value semicolons before expansion in foreach below. + string(REPLACE ";" "\\;" tmp "${arg}") # Split argument into DATA{}-pieces and other pieces. - string(REGEX MATCHALL "${data_regex}|${other_regex}" pieces "${arg}") + string(REGEX MATCHALL "${data_regex}|${other_regex}" pieces "${tmp}") # Compose output argument with DATA{}-pieces replaced. set(outArg "") foreach(piece IN LISTS pieces) @@ -254,11 +259,13 @@ function(ExternalData_expand_arguments target outArgsVar) set(outArg "${outArg}${piece}") endif() endforeach() - list(APPEND outArgs "${outArg}") else() # No replacements needed in this argument. - list(APPEND outArgs "${arg}") + set(outArg "${arg}") endif() + # Re-escape in-value semicolons in resulting list. + string(REPLACE ";" "\\;" outArg "${outArg}") + list(APPEND outArgs "${outArg}") endforeach() set("${outArgsVar}" "${outArgs}" PARENT_SCOPE) endfunction() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8dd9dd8..6f3e6ef 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -2,5 +2,5 @@ set(CMake_VERSION_MAJOR 2) set(CMake_VERSION_MINOR 8) set(CMake_VERSION_PATCH 10) -set(CMake_VERSION_TWEAK 20130312) +set(CMake_VERSION_TWEAK 20130313) #set(CMake_VERSION_RC 1) diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx index 9efeda4..5b1c9c6 100644 --- a/Source/cmAddSubDirectoryCommand.cxx +++ b/Source/cmAddSubDirectoryCommand.cxx @@ -78,7 +78,7 @@ bool cmAddSubDirectoryCommand::InitialPass // No binary directory was specified. If the source directory is // not a subdirectory of the current directory then it is an // error. - if(!cmSystemTools::FindLastString(srcPath.c_str(), + if(!cmSystemTools::IsSubDirectory(srcPath.c_str(), this->Makefile->GetCurrentDirectory())) { cmOStringStream e; @@ -93,10 +93,15 @@ bool cmAddSubDirectoryCommand::InitialPass // Remove the CurrentDirectory from the srcPath and replace it // with the CurrentOutputDirectory. - binPath = srcPath; - cmSystemTools::ReplaceString(binPath, - this->Makefile->GetCurrentDirectory(), - this->Makefile->GetCurrentOutputDirectory()); + const char* src = this->Makefile->GetCurrentDirectory(); + const char* bin = this->Makefile->GetCurrentOutputDirectory(); + size_t srcLen = strlen(src); + size_t binLen = strlen(bin); + if(srcLen > 0 && src[srcLen-1] == '/') + { --srcLen; } + if(binLen > 0 && bin[binLen-1] == '/') + { --binLen; } + binPath = std::string(bin, binLen) + srcPath.substr(srcLen); } else { diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 76a60c3..6cc3f25 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -26,6 +26,8 @@ "strings which contain a '>' for example.\n" \ " $<COMMA> = A literal ','. Used to compare " \ "strings which contain a ',' for example.\n" \ + " $<SEMICOLON> = A literal ';'. Used to prevent " \ + "list expansion on an argument with ';'.\n" \ " $<TARGET_NAME:...> = Marks ... as being the name of a " \ "target. This is required if exporting targets to multiple " \ "dependent export sets. The '...' must be a literal name of a " \ diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index 204bd9a..326a4ce 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -1551,7 +1551,14 @@ void cmDocumentVariables::DefineVariables(cmake* cm) ("CMAKE_COMPILER_IS_GNU<LANG>", cmProperty::VARIABLE, "True if the compiler is GNU.", "If the selected <LANG> compiler is the GNU " - "compiler then this is TRUE, if not it is FALSE.",false, + "compiler then this is TRUE, if not it is FALSE. " + "Unlike the other per-language variables, this uses the GNU syntax for " + "identifying languages instead of the CMake syntax. Recognized values of " + "the <LANG> suffix are:\n" + " CC = C compiler\n" + " CXX = C++ compiler\n" + " G77 = Fortran compiler", + false, "Variables for Languages"); cm->DefineProperty diff --git a/Source/cmEnableLanguageCommand.h b/Source/cmEnableLanguageCommand.h index e4bb251..ee963f9 100644 --- a/Source/cmEnableLanguageCommand.h +++ b/Source/cmEnableLanguageCommand.h @@ -65,7 +65,12 @@ public: "any of the extra variables that are created by the project command. " "Example languages are CXX, C, Fortran. " "If OPTIONAL is used, use the CMAKE_<languageName>_COMPILER_WORKS " - "variable to check whether the language has been enabled successfully."; + "variable to check whether the language has been enabled successfully." + "\n" + "This command must be called on file scope (not inside a function) and " + "the language enabled can only be used in the calling project or its " + "subdirectories added by add_subdirectory(). Also note that at present, " + "the OPTIONAL argument does not work."; } cmTypeMacro(cmEnableLanguageCommand, cmCommand); diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index e2d8777..6618e83 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -227,6 +227,22 @@ static const struct CommaNode : public cmGeneratorExpressionNode } commaNode; //---------------------------------------------------------------------------- +static const struct SemicolonNode : public cmGeneratorExpressionNode +{ + SemicolonNode() {} + + virtual int NumExpectedParameters() const { return 0; } + + std::string Evaluate(const std::vector<std::string> &, + cmGeneratorExpressionContext *, + const GeneratorExpressionContent *, + cmGeneratorExpressionDAGChecker *) const + { + return ";"; + } +} semicolonNode; + +//---------------------------------------------------------------------------- static const struct ConfigurationNode : public cmGeneratorExpressionNode { ConfigurationNode() {} @@ -943,6 +959,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &angle_rNode; else if (identifier == "COMMA") return &commaNode; + else if (identifier == "SEMICOLON") + return &semicolonNode; else if (identifier == "TARGET_PROPERTY") return &targetPropertyNode; else if (identifier == "TARGET_NAME") diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index fcd6f71..df14331 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1086,8 +1086,10 @@ void cmGlobalGenerator::CreateAutomocTargets() if(target.GetPropertyAsBool("AUTOMOC") && !target.IsImported()) { cmQtAutomoc automoc; - automoc.InitializeMocSourceFile(&target); - automocs.push_back(std::make_pair(automoc, &target)); + if(automoc.InitializeMocSourceFile(&target)) + { + automocs.push_back(std::make_pair(automoc, &target)); + } } } } diff --git a/Source/cmQtAutomoc.cxx b/Source/cmQtAutomoc.cxx index 10ce641..5730c8c 100644 --- a/Source/cmQtAutomoc.cxx +++ b/Source/cmQtAutomoc.cxx @@ -119,10 +119,21 @@ cmQtAutomoc::cmQtAutomoc() } } -void cmQtAutomoc::InitializeMocSourceFile(cmTarget* target) +bool cmQtAutomoc::InitializeMocSourceFile(cmTarget* target) { + cmMakefile* makefile = target->GetMakefile(); + // don't do anything if there is no Qt4 or Qt5Core (which contains moc): + std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); + if (qtMajorVersion == "") + { + qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); + } + if (qtMajorVersion != "4" && qtMajorVersion != "5") + { + return false; + } + std::string automocTargetName = target->GetName(); - cmMakefile *makefile = target->GetMakefile(); automocTargetName += "_automoc"; std::string mocCppFile = makefile->GetCurrentOutputDirectory(); mocCppFile += "/"; @@ -134,6 +145,7 @@ void cmQtAutomoc::InitializeMocSourceFile(cmTarget* target) mocCppFile.c_str(), false); target->AddSourceFile(mocCppSource); + return true; } void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) @@ -141,16 +153,6 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target) cmMakefile* makefile = target->GetMakefile(); cmLocalGenerator* localGen = makefile->GetLocalGenerator(); const char* targetName = target->GetName(); - // don't do anything if there is no Qt4 or Qt5Core (which contains moc): - std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); - if (qtMajorVersion == "") - { - qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); - } - if (qtMajorVersion != "4" && qtMajorVersion != "5") - { - return; - } bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE"); diff --git a/Source/cmQtAutomoc.h b/Source/cmQtAutomoc.h index 962e254..01b68fc 100644 --- a/Source/cmQtAutomoc.h +++ b/Source/cmQtAutomoc.h @@ -23,7 +23,7 @@ public: cmQtAutomoc(); bool Run(const char* targetDirectory); - void InitializeMocSourceFile(cmTarget* target); + bool InitializeMocSourceFile(cmTarget* target); void SetupAutomocTarget(cmTarget* target); private: diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index 4423a90..30dbaa5 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -136,6 +136,9 @@ public: " [^ ] Matches any character(s) not inside the brackets\n" " - Inside brackets, specifies an inclusive range between\n" " characters on either side e.g. [a-f] is [abcdef]\n" + " To match a literal - using brackets, make it the first\n" + " or the last character e.g. [+*/-] matches basic\n" + " mathematical operators.\n" " * Matches preceding pattern zero or more times\n" " + Matches preceding pattern one or more times\n" " ? Matches preceding pattern zero or once only\n" @@ -144,6 +147,10 @@ public: " in the REGEX REPLACE operation. Additionally it is saved\n" " by all regular expression-related commands, including \n" " e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9).\n" + "*, + and ? have higher precedence than concatenation. | has lower " + "precedence than concatenation. This means that the regular expression " + "\"^ab+d$\" matches \"abbd\" but not \"ababd\", and the regular " + "expression \"^(ab|cd)$\" matches \"ab\" but not \"abd\".\n" "TIMESTAMP will write a string representation of " "the current date and/or time to the output variable.\n" "Should the command be unable to obtain a timestamp " diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index d46325b..e0d7fa4 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1232,7 +1232,9 @@ void cmTarget::DefineProperties(cmake *cm) ("GENERATOR_FILE_NAME", cmProperty::TARGET, "Generator's file for this target.", "An internal property used by some generators to record the name of " - "project or dsp file associated with this target."); + "project or dsp file associated with this target. Note that at configure " + "time, this property is only set for targets created by " + "include_external_msproject()."); cm->DefineProperty ("SOURCES", cmProperty::TARGET, @@ -4751,6 +4753,10 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt, || (!impliedByUse && !explicitlySet)); cmComputeLinkInformation *info = tgt->GetLinkInformation(config); + if(!info) + { + return propContent; + } const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); bool propInitialized = explicitlySet; @@ -4891,6 +4897,10 @@ bool isLinkDependentProperty(cmTarget *tgt, const std::string &p, const char *config) { cmComputeLinkInformation *info = tgt->GetLinkInformation(config); + if(!info) + { + return false; + } const cmComputeLinkInformation::ItemVector &deps = info->GetItems(); diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 8c7b87c..5982e8b 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -993,6 +993,16 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Environment") + add_test(QtAutomocNoQt ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/QtAutomocNoQt" + "${CMake_BINARY_DIR}/Tests/QtAutomocNoQt" + ${build_generator_args} + --build-project QtAutomocNoQt + --build-options -DCMAKE_BUILD_TYPE=\${CTEST_CONFIGURATION_TYPE} + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomocNoQt") + if(QT4_WORKS AND QT_QTGUI_FOUND) add_test(QtAutomoc ${CMAKE_CTEST_COMMAND} --build-and-test diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index fff7c87..0008c16 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -47,11 +47,13 @@ add_custom_target(check-part1 ALL -Dtest_strequal_no_yes=$<STREQUAL:No,Yes> -Dtest_strequal_angle_r=$<STREQUAL:$<ANGLE-R>,$<ANGLE-R>> -Dtest_strequal_comma=$<STREQUAL:$<COMMA>,$<COMMA>> + -Dtest_strequal_semicolon=$<STREQUAL:$<SEMICOLON>,$<SEMICOLON>> -Dtest_strequal_angle_r_comma=$<STREQUAL:$<ANGLE-R>,$<COMMA>> -Dtest_strequal_both_empty=$<STREQUAL:,> -Dtest_strequal_one_empty=$<STREQUAL:something,> -Dtest_angle_r=$<ANGLE-R> -Dtest_comma=$<COMMA> + -Dtest_semicolon=$<SEMICOLON> -Dtest_colons_1=$<1::> -Dtest_colons_2=$<1:::> -Dtest_colons_3=$<1:Qt5::Core> diff --git a/Tests/GeneratorExpression/check-part1.cmake b/Tests/GeneratorExpression/check-part1.cmake index 7abfa82..9bef159 100644 --- a/Tests/GeneratorExpression/check-part1.cmake +++ b/Tests/GeneratorExpression/check-part1.cmake @@ -44,11 +44,13 @@ check(test_strequal_yes_no "0") check(test_strequal_no_yes "0") check(test_strequal_angle_r "1") check(test_strequal_comma "1") +check(test_strequal_semicolon "1") check(test_strequal_angle_r_comma "0") check(test_strequal_both_empty "1") check(test_strequal_one_empty "0") check(test_angle_r ">") check(test_comma ",") +check(test_semicolon ";") check(test_colons_1 ":") check(test_colons_2 "::") check(test_colons_3 "Qt5::Core") diff --git a/Tests/Module/ExternalData/CMakeLists.txt b/Tests/Module/ExternalData/CMakeLists.txt index a379dca..8312dca 100644 --- a/Tests/Module/ExternalData/CMakeLists.txt +++ b/Tests/Module/ExternalData/CMakeLists.txt @@ -35,6 +35,7 @@ ExternalData_Add_Test(Data1 -D Paired=DATA{PairedA.dat,PairedB.dat} -D Meta=DATA{MetaTop.dat,REGEX:Meta[ABC].dat} -D Directory=DATA{Directory/,A.dat,REGEX:[BC].dat} + -D "Semicolons=DATA{Data.dat}\\;DATA{Data.dat}" -P ${CMAKE_CURRENT_SOURCE_DIR}/Data1Check.cmake ) ExternalData_Add_Target(Data1) diff --git a/Tests/Module/ExternalData/Data1Check.cmake b/Tests/Module/ExternalData/Data1Check.cmake index f40b76c..5770245 100644 --- a/Tests/Module/ExternalData/Data1Check.cmake +++ b/Tests/Module/ExternalData/Data1Check.cmake @@ -56,3 +56,13 @@ foreach(n A B C) message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!") endif() endforeach() +list(LENGTH Semicolons len) +if("${len}" EQUAL 2) + foreach(file ${Semicolons}) + if(NOT EXISTS "${file}") + message(SEND_ERROR "Input file:\n ${file}\ndoes not exist!") + endif() + endforeach() +else() + message(SEND_ERROR "Semicolons value:\n ${Semicolons}\nis not a list of length 2.") +endif() diff --git a/Tests/QtAutomocNoQt/CMakeLists.txt b/Tests/QtAutomocNoQt/CMakeLists.txt new file mode 100644 index 0000000..b26e471 --- /dev/null +++ b/Tests/QtAutomocNoQt/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8) + +project(QtAutomocNoQt) + +set(CMAKE_AUTOMOC ON) + +add_executable(hello main.c) diff --git a/Tests/QtAutomocNoQt/main.c b/Tests/QtAutomocNoQt/main.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/QtAutomocNoQt/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/ExternalData/RunCMakeTest.cmake b/Tests/RunCMake/ExternalData/RunCMakeTest.cmake index 5ee46c9..ceb2ecf 100644 --- a/Tests/RunCMake/ExternalData/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExternalData/RunCMakeTest.cmake @@ -21,4 +21,7 @@ run_cmake(NormalData2) run_cmake(NormalData3) run_cmake(NormalDataSub1) run_cmake(NotUnderRoot) +run_cmake(Semicolon1) +run_cmake(Semicolon2) +run_cmake(Semicolon3) run_cmake(SubDirectory1) diff --git a/Tests/RunCMake/ExternalData/Semicolon1-stdout.txt b/Tests/RunCMake/ExternalData/Semicolon1-stdout.txt new file mode 100644 index 0000000..361baeb --- /dev/null +++ b/Tests/RunCMake/ExternalData/Semicolon1-stdout.txt @@ -0,0 +1 @@ +-- Data arguments correctly transformed! diff --git a/Tests/RunCMake/ExternalData/Semicolon1.cmake b/Tests/RunCMake/ExternalData/Semicolon1.cmake new file mode 100644 index 0000000..c832860 --- /dev/null +++ b/Tests/RunCMake/ExternalData/Semicolon1.cmake @@ -0,0 +1,14 @@ +include(ExternalData) +set(ExternalData_URL_TEMPLATES + "file:///${CMAKE_CURRENT_SOURCE_DIR}/%(algo)/%(hash)" + ) +set(input Data.txt) +set(output ${CMAKE_CURRENT_BINARY_DIR}/Data.txt) +ExternalData_Expand_Arguments(Data args DATA{${input}} "a\\;b" "c;d" DATA{${input}}) +set(expect "${output};a\\;b;c;d;${output}") +if("x${args}" STREQUAL "x${expect}") + message(STATUS "Data arguments correctly transformed!") +else() + message(FATAL_ERROR "Data arguments transformed to:\n ${args}\n" + "but we expected:\n ${expect}") +endif() diff --git a/Tests/RunCMake/ExternalData/Semicolon2-stdout.txt b/Tests/RunCMake/ExternalData/Semicolon2-stdout.txt new file mode 100644 index 0000000..361baeb --- /dev/null +++ b/Tests/RunCMake/ExternalData/Semicolon2-stdout.txt @@ -0,0 +1 @@ +-- Data arguments correctly transformed! diff --git a/Tests/RunCMake/ExternalData/Semicolon2.cmake b/Tests/RunCMake/ExternalData/Semicolon2.cmake new file mode 100644 index 0000000..1a1ae5f --- /dev/null +++ b/Tests/RunCMake/ExternalData/Semicolon2.cmake @@ -0,0 +1,14 @@ +include(ExternalData) +set(ExternalData_URL_TEMPLATES + "file:///${CMAKE_CURRENT_SOURCE_DIR}/%(algo)/%(hash)" + ) +set(input Data.txt) +set(output ${CMAKE_CURRENT_BINARY_DIR}/Data.txt) +ExternalData_Expand_Arguments(Data args "DATA{${input}};a\\;b;c;d;DATA{${input}}") +set(expect "${output};a\\;b;c;d;${output}") +if("x${args}" STREQUAL "x${expect}") + message(STATUS "Data arguments correctly transformed!") +else() + message(FATAL_ERROR "Data arguments transformed to:\n ${args}\n" + "but we expected:\n ${expect}") +endif() diff --git a/Tests/RunCMake/ExternalData/Semicolon3-stdout.txt b/Tests/RunCMake/ExternalData/Semicolon3-stdout.txt new file mode 100644 index 0000000..ca4a360 --- /dev/null +++ b/Tests/RunCMake/ExternalData/Semicolon3-stdout.txt @@ -0,0 +1 @@ +-- Data arguments correctly not transformed! diff --git a/Tests/RunCMake/ExternalData/Semicolon3.cmake b/Tests/RunCMake/ExternalData/Semicolon3.cmake new file mode 100644 index 0000000..2ae99da --- /dev/null +++ b/Tests/RunCMake/ExternalData/Semicolon3.cmake @@ -0,0 +1,12 @@ +include(ExternalData) +set(ExternalData_URL_TEMPLATES + "file:///${CMAKE_CURRENT_SOURCE_DIR}/%(algo)/%(hash)" + ) +set(input "DATA{a;b}") +ExternalData_Expand_Arguments(Data args "${input}") +if("x${args}" STREQUAL "x${input}") + message(STATUS "Data arguments correctly not transformed!") +else() + message(FATAL_ERROR "Data arguments transformed to:\n ${args}\n" + "but we expected:\n ${input}") +endif() |