From 601e6e1ad10b83dcb5ad09d061b04e6974cda283 Mon Sep 17 00:00:00 2001 From: Gregor Jasny Date: Sun, 18 Oct 2015 21:53:12 +0200 Subject: [PATCH] Xcode: Use regular expression to extract all optimisation flags (#15794) --- Source/cmGlobalXCodeGenerator.cxx | 50 +++++++++++++++---- Source/cmGlobalXCodeGenerator.h | 2 + .../RunCMake/XcodeProject/RunCMakeTest.cmake | 3 ++ .../XcodeOptimizationFlags-check.cmake | 7 +++ .../XcodeProject/XcodeOptimizationFlags.cmake | 20 ++++++++ ...dePreserveNonOptimizationFlags-check.cmake | 8 +++ .../XcodePreserveNonOptimizationFlags.cmake | 12 +++++ .../XcodePreserveObjcFlag-check.cmake | 7 +++ .../XcodeProject/XcodePreserveObjcFlag.cmake | 6 +++ 9 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 Tests/RunCMake/XcodeProject/XcodeOptimizationFlags-check.cmake create mode 100644 Tests/RunCMake/XcodeProject/XcodeOptimizationFlags.cmake create mode 100644 Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags-check.cmake create mode 100644 Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags.cmake create mode 100644 Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag-check.cmake create mode 100644 Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag.cmake diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index bc05aeadc..0e3af883e 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1611,6 +1611,39 @@ std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag, return retFlag; } +//---------------------------------------------------------------------------- +// This function removes each matching occurrence of the expression and +// returns the last one (i.e., the dominant flag in GCC) +std::string cmGlobalXCodeGenerator::ExtractFlagRegex(const char* exp, + int matchIndex, + std::string& flags) +{ + std::string retFlag; + + cmsys::RegularExpression regex(exp); + assert(regex.is_valid()); + if(!regex.is_valid()) + { + return retFlag; + } + + std::string::size_type offset = 0; + + while(regex.find(flags.c_str() + offset)) + { + const std::string::size_type startPos = offset + regex.start(matchIndex); + const std::string::size_type endPos = offset + regex.end(matchIndex); + const std::string::size_type size = endPos - startPos; + + offset = startPos + 1; + + retFlag.assign(flags, startPos, size); + flags.replace(startPos, size, size, ' '); + } + + return retFlag; +} + //---------------------------------------------------------------------------- void cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase, @@ -2227,9 +2260,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, bool same_gflags = true; std::map gflags; std::string const* last_gflag = 0; - char optLevel[2]; - optLevel[0] = '0'; - optLevel[1] = 0; + std::string optLevel = "0"; // Minimal map of flags to build settings. for (std::set::iterator li = languages.begin(); @@ -2237,14 +2268,15 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, { std::string& flags = cflags[*li]; std::string& gflag = gflags[*li]; - std::string oflag = this->ExtractFlag("-O", flags); - if(oflag.size() == 3) - { - optLevel[0] = oflag[2]; - } + std::string oflag = + this->ExtractFlagRegex("(^| )(-Ofast|-Os|-O[0-9]*)( |$)", 2, flags); if(oflag.size() == 2) { - optLevel[0] = '1'; + optLevel = "1"; + } + else if(oflag.size() > 2) + { + optLevel = oflag.substr(2); } gflag = this->ExtractFlag("-g", flags); // put back gdwarf-2 if used since there is no way diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 9daf0abd6..791324daa 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -151,6 +151,8 @@ private: cmXCodeObject* buildSettings, const std::string& buildType); std::string ExtractFlag(const char* flag, std::string& flags); + std::string ExtractFlagRegex(const char* exp, int matchIndex, + std::string& flags); void SortXCodeObjects(); // delete all objects in the this->XCodeObjects vector. void ClearXCodeObjects(); diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake index 8ab618bbf..7901ec002 100644 --- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake @@ -4,6 +4,9 @@ run_cmake(XcodeFileType) run_cmake(XcodeAttributeGenex) run_cmake(XcodeAttributeGenexError) run_cmake(XcodeObjectNeedsQuote) +run_cmake(XcodeOptimizationFlags) +run_cmake(XcodePreserveNonOptimizationFlags) +run_cmake(XcodePreserveObjcFlag) if (NOT XCODE_VERSION VERSION_LESS 6) run_cmake(XcodePlatformFrameworks) endif() diff --git a/Tests/RunCMake/XcodeProject/XcodeOptimizationFlags-check.cmake b/Tests/RunCMake/XcodeProject/XcodeOptimizationFlags-check.cmake new file mode 100644 index 000000000..f5595b315 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodeOptimizationFlags-check.cmake @@ -0,0 +1,7 @@ +foreach(level 1 2 3 s fast) + file(STRINGS ${RunCMake_TEST_BINARY_DIR}/XcodeOptimizationFlags.xcodeproj/project.pbxproj actual-${level} + REGEX "GCC_OPTIMIZATION_LEVEL = ${level};" LIMIT_COUNT 1) + if(NOT actual-${level}) + message(SEND_ERROR "Optimization level '${level}' not found in Xcode project.") + endif() +endforeach() diff --git a/Tests/RunCMake/XcodeProject/XcodeOptimizationFlags.cmake b/Tests/RunCMake/XcodeProject/XcodeOptimizationFlags.cmake new file mode 100644 index 000000000..e14bf808d --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodeOptimizationFlags.cmake @@ -0,0 +1,20 @@ +set(CMAKE_CONFIGURATION_TYPES "Release" CACHE INTERNAL "Supported configuration types") + +set(CMAKE_CXX_FLAGS_RELEASE "") + +project(XcodeOptimizationFlags CXX) + +add_library(fooO1 STATIC foo.cpp) +set_target_properties(fooO1 PROPERTIES COMPILE_OPTIONS -O1) + +add_library(fooO2 STATIC foo.cpp) +set_target_properties(fooO2 PROPERTIES COMPILE_OPTIONS -O2) + +add_library(fooO3 STATIC foo.cpp) +set_target_properties(fooO3 PROPERTIES COMPILE_OPTIONS -O3) + +add_library(fooOs STATIC foo.cpp) +set_target_properties(fooOs PROPERTIES COMPILE_OPTIONS -Os) + +add_library(fooOfast STATIC foo.cpp) +set_target_properties(fooOfast PROPERTIES COMPILE_OPTIONS -Ofast) diff --git a/Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags-check.cmake b/Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags-check.cmake new file mode 100644 index 000000000..2f6c03d20 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags-check.cmake @@ -0,0 +1,8 @@ +file(STRINGS ${RunCMake_TEST_BINARY_DIR}/XcodePreserveNonOptimizationFlags.xcodeproj/project.pbxproj actual + REGEX "OTHER_CPLUSPLUSFLAGS = [^;]*;") +foreach(expect "-DA" "-DB +-DC" "-DD") + if(NOT "${actual}" MATCHES "${expect}") + message(SEND_ERROR "The actual project contains the lines:\n ${actual}\n" + "which do not match expected regex:\n ${expect}\n") + endif() +endforeach() diff --git a/Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags.cmake b/Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags.cmake new file mode 100644 index 000000000..16f038184 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodePreserveNonOptimizationFlags.cmake @@ -0,0 +1,12 @@ +set(CMAKE_CONFIGURATION_TYPES "Release" CACHE INTERNAL "Supported configuration types") + +project(XcodePreserveNonOptimizationFlags CXX) + +add_library(preserveStart STATIC foo.cpp) +set_property(TARGET preserveStart PROPERTY COMPILE_OPTIONS -DA -O1) + +add_library(preserveBoth STATIC foo.cpp) +set_property(TARGET preserveBoth PROPERTY COMPILE_OPTIONS -DB -O1 -DC) + +add_library(preserveEnd STATIC foo.cpp) +set_property(TARGET preserveEnd PROPERTY COMPILE_OPTIONS -O1 -DD) diff --git a/Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag-check.cmake b/Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag-check.cmake new file mode 100644 index 000000000..332906f8e --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag-check.cmake @@ -0,0 +1,7 @@ +set(expect "-ObjC") +file(STRINGS ${RunCMake_TEST_BINARY_DIR}/XcodePreserveObjcFlag.xcodeproj/project.pbxproj actual + REGEX "OTHER_CPLUSPLUSFLAGS = [^;]*;" LIMIT_COUNT 1) +if(NOT "${actual}" MATCHES "${expect}") + message(SEND_ERROR "The actual project contains the line:\n ${actual}\n" + "which does not match expected regex:\n ${expect}\n") +endif() diff --git a/Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag.cmake b/Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag.cmake new file mode 100644 index 000000000..64db63334 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodePreserveObjcFlag.cmake @@ -0,0 +1,6 @@ +set(CMAKE_CONFIGURATION_TYPES "Release" CACHE INTERNAL "Supported configuration types") + +project(XcodePreserveObjcFlag CXX) + +add_library(foo STATIC foo.cpp) +set_target_properties(foo PROPERTIES COMPILE_OPTIONS -ObjC)