From 8262ccfd4efddd4928070c637ef7c414633b4b1e Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 14 Jan 2008 09:20:58 -0500 Subject: ENH: Create COMPILE_DEFINITIONS property for targets and source files. Create _COMPILE_DEFINITIONS property as per-configuration version. Add Preprocess test to test the feature. Document limitations on Xcode and VS6 generators. --- Modules/CMakeCInformation.cmake | 2 +- Modules/CMakeCXXInformation.cmake | 2 +- Modules/Platform/AIX.cmake | 10 +- Modules/Platform/Generic-SDCC-C.cmake | 2 +- Modules/Platform/QNX.cmake | 2 +- Modules/Platform/Windows-bcc32.cmake | 8 +- Modules/Platform/Windows-icl.cmake | 4 +- Modules/Platform/Windows-wcl386.cmake | 8 +- Modules/Platform/cl.cmake | 8 +- Source/cmGlobalXCodeGenerator.cxx | 92 +++++++++- Source/cmGlobalXCodeGenerator.h | 3 + Source/cmLocalGenerator.cxx | 117 ++++++++++++ Source/cmLocalGenerator.h | 11 ++ Source/cmLocalUnixMakefileGenerator3.cxx | 12 +- Source/cmLocalVisualStudio6Generator.cxx | 76 +++++++- Source/cmLocalVisualStudio6Generator.h | 3 + Source/cmLocalVisualStudio7Generator.cxx | 301 +++++++++++++++++++------------ Source/cmLocalVisualStudio7Generator.h | 6 +- Source/cmMakefileTargetGenerator.cxx | 53 +++++- Source/cmSourceFile.cxx | 28 ++- Source/cmTarget.cxx | 28 ++- Tests/CMakeLists.txt | 1 + Tests/Preprocess/CMakeLists.txt | 181 +++++++++++++++++++ Tests/Preprocess/file_def.h | 1 + Tests/Preprocess/preprocess.c | 170 +++++++++++++++++ Tests/Preprocess/preprocess.cxx | 197 ++++++++++++++++++++ Tests/Preprocess/preprocess.h.in | 16 ++ Tests/Preprocess/preprocess_vs6.cxx | 3 + Tests/Preprocess/target_def.h | 1 + 29 files changed, 1184 insertions(+), 162 deletions(-) create mode 100644 Tests/Preprocess/CMakeLists.txt create mode 100644 Tests/Preprocess/file_def.h create mode 100644 Tests/Preprocess/preprocess.c create mode 100644 Tests/Preprocess/preprocess.cxx create mode 100644 Tests/Preprocess/preprocess.h.in create mode 100644 Tests/Preprocess/preprocess_vs6.cxx create mode 100644 Tests/Preprocess/target_def.h diff --git a/Modules/CMakeCInformation.cmake b/Modules/CMakeCInformation.cmake index 543c396..f02d47c 100644 --- a/Modules/CMakeCInformation.cmake +++ b/Modules/CMakeCInformation.cmake @@ -141,7 +141,7 @@ ENDIF(NOT CMAKE_C_CREATE_STATIC_LIBRARY) # compile a C file into an object file IF(NOT CMAKE_C_COMPILE_OBJECT) SET(CMAKE_C_COMPILE_OBJECT - " -o -c ") + " -o -c ") ENDIF(NOT CMAKE_C_COMPILE_OBJECT) IF(NOT CMAKE_C_LINK_EXECUTABLE) diff --git a/Modules/CMakeCXXInformation.cmake b/Modules/CMakeCXXInformation.cmake index 3d8460b..256cee1 100644 --- a/Modules/CMakeCXXInformation.cmake +++ b/Modules/CMakeCXXInformation.cmake @@ -201,7 +201,7 @@ ENDIF(NOT CMAKE_CXX_CREATE_STATIC_LIBRARY) # compile a C++ file into an object file IF(NOT CMAKE_CXX_COMPILE_OBJECT) SET(CMAKE_CXX_COMPILE_OBJECT - " -o -c ") + " -o -c ") ENDIF(NOT CMAKE_CXX_COMPILE_OBJECT) IF(NOT CMAKE_CXX_LINK_EXECUTABLE) diff --git a/Modules/Platform/AIX.cmake b/Modules/Platform/AIX.cmake index 4c580fe..13a00a0 100644 --- a/Modules/Platform/AIX.cmake +++ b/Modules/Platform/AIX.cmake @@ -33,15 +33,15 @@ ELSE(CMAKE_COMPILER_IS_GNUCC) ENDIF(CMAKE_COMPILER_IS_GNUCC) IF(NOT CMAKE_COMPILER_IS_GNUCC) - SET (CMAKE_C_CREATE_PREPROCESSED_SOURCE " -E > ") - SET (CMAKE_C_CREATE_ASSEMBLY_SOURCE " -S -o ") + SET (CMAKE_C_CREATE_PREPROCESSED_SOURCE " -E > ") + SET (CMAKE_C_CREATE_ASSEMBLY_SOURCE " -S -o ") ENDIF(NOT CMAKE_COMPILER_IS_GNUCC) IF(NOT CMAKE_COMPILER_IS_GNUCXX) SET(CMAKE_CXX_COMPILE_OBJECT - " -+ -o -c ") - SET (CMAKE_CXX_CREATE_PREPROCESSED_SOURCE " -E > ") - SET (CMAKE_CXX_CREATE_ASSEMBLY_SOURCE " -S -o ") + " -+ -o -c ") + SET (CMAKE_CXX_CREATE_PREPROCESSED_SOURCE " -E > ") + SET (CMAKE_CXX_CREATE_ASSEMBLY_SOURCE " -S -o ") ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX) diff --git a/Modules/Platform/Generic-SDCC-C.cmake b/Modules/Platform/Generic-SDCC-C.cmake index fe94c3c..ac81c35 100644 --- a/Modules/Platform/Generic-SDCC-C.cmake +++ b/Modules/Platform/Generic-SDCC-C.cmake @@ -38,7 +38,7 @@ IF(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT) ENDIF(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT) # compile a C file into an object file -SET(CMAKE_C_COMPILE_OBJECT " -o -c ") +SET(CMAKE_C_COMPILE_OBJECT " -o -c ") # link object files to an executable SET(CMAKE_C_LINK_EXECUTABLE " --out-fmt-ihx -o ") diff --git a/Modules/Platform/QNX.cmake b/Modules/Platform/QNX.cmake index 728b9ae..e706a59 100644 --- a/Modules/Platform/QNX.cmake +++ b/Modules/Platform/QNX.cmake @@ -28,6 +28,6 @@ FOREACH(type SHARED_LIBRARY SHARED_MODULE EXE) ENDFOREACH(type) # force the language to be c++ since qnx only has gcc and not g++ and c++? SET(CMAKE_CXX_COMPILE_OBJECT - " -x c++ -o -c ") + " -x c++ -o -c ") INCLUDE(Platform/UnixPaths) diff --git a/Modules/Platform/Windows-bcc32.cmake b/Modules/Platform/Windows-bcc32.cmake index d333863..2060dc2 100644 --- a/Modules/Platform/Windows-bcc32.cmake +++ b/Modules/Platform/Windows-bcc32.cmake @@ -63,12 +63,16 @@ SET(CMAKE_CXX_CREATE_STATIC_LIBRARY "tlib ${CMAKE_START_TEMP_FILE}/p512 outside the response file because Borland refuses +# to parse quotes from the response file. SET(CMAKE_CXX_COMPILE_OBJECT - " ${CMAKE_START_TEMP_FILE}-DWIN32 -P -o -c ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE}-DWIN32 -P -o -c ${CMAKE_END_TEMP_FILE}") # compile a C file into an object file +# place outside the response file because Borland refuses +# to parse quotes from the response file. SET(CMAKE_C_COMPILE_OBJECT - " ${CMAKE_START_TEMP_FILE}-DWIN32 -o -c ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE}-DWIN32 -o -c ${CMAKE_END_TEMP_FILE}") SET(CMAKE_C_LINK_EXECUTABLE diff --git a/Modules/Platform/Windows-icl.cmake b/Modules/Platform/Windows-icl.cmake index d09eb1c..d6db61b 100644 --- a/Modules/Platform/Windows-icl.cmake +++ b/Modules/Platform/Windows-icl.cmake @@ -27,11 +27,11 @@ SET(CMAKE_C_CREATE_STATIC_LIBRARY ${CMAKE_CXX_CREATE_STATIC_LIBRARY}) # compile a C++ file into an object file SET(CMAKE_CXX_COMPILE_OBJECT - " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP -DWIN32 /Fo -c ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP -DWIN32 /Fo -c ${CMAKE_END_TEMP_FILE}") # compile a C file into an object file SET(CMAKE_C_COMPILE_OBJECT - " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} -DWIN32 /Fo -c ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} -DWIN32 /Fo -c ${CMAKE_END_TEMP_FILE}") SET(CMAKE_C_LINK_EXECUTABLE diff --git a/Modules/Platform/Windows-wcl386.cmake b/Modules/Platform/Windows-wcl386.cmake index e19b4aa..a98bcaf 100644 --- a/Modules/Platform/Windows-wcl386.cmake +++ b/Modules/Platform/Windows-wcl386.cmake @@ -36,19 +36,19 @@ SET(CMAKE_CXX_LINK_EXECUTABLE ${CMAKE_C_LINK_EXECUTABLE}) # compile a C++ file into an object file SET(CMAKE_CXX_COMPILE_OBJECT - " ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} -dWIN32 -fo -c -cc++ ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} -dWIN32 -d+ -fo -c -cc++ ${CMAKE_END_TEMP_FILE}") # compile a C file into an object file SET(CMAKE_C_COMPILE_OBJECT - " ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} -dWIN32 -fo -c -cc ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} -dWIN32 -d+ -fo -c -cc ${CMAKE_END_TEMP_FILE}") # preprocess a C source file SET(CMAKE_C_CREATE_PREPROCESSED_SOURCE - " ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} -dWIN32 -fo -pl -cc ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} -dWIN32 -d+ -fo -pl -cc ${CMAKE_END_TEMP_FILE}") # preprocess a C++ source file SET(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE - " ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} -dWIN32 -fo -pl -cc++ ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} -dWIN32 -d+ -fo -pl -cc++ ${CMAKE_END_TEMP_FILE}") SET(CMAKE_CXX_CREATE_SHARED_MODULE "wlink ${CMAKE_START_TEMP_FILE} system nt_dll ${CMAKE_WLINK_QUIET} name option caseexact file {} ${CMAKE_END_TEMP_FILE}") diff --git a/Modules/Platform/cl.cmake b/Modules/Platform/cl.cmake index eba5c32..6afb73f 100644 --- a/Modules/Platform/cl.cmake +++ b/Modules/Platform/cl.cmake @@ -34,11 +34,11 @@ SET(CMAKE_C_CREATE_STATIC_LIBRARY "${CMAKE_CXX_CREATE_STATIC_LIBRARY}") # compile a C++ file into an object file SET(CMAKE_CXX_COMPILE_OBJECT - " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP /Fo /Fd -c ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP /Fo /Fd -c ${CMAKE_END_TEMP_FILE}") # compile a C file into an object file SET(CMAKE_C_COMPILE_OBJECT - " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /Fo /Fd -c ${CMAKE_END_TEMP_FILE}") + " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /Fo /Fd -c ${CMAKE_END_TEMP_FILE}") SET(CMAKE_C_LINK_EXECUTABLE @@ -48,10 +48,10 @@ SET(CMAKE_CXX_LINK_EXECUTABLE " ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} /Fe /Fd -link /implib: /version:. ${CMAKE_END_TEMP_FILE}") SET(CMAKE_C_CREATE_PREPROCESSED_SOURCE - " > ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} -E ${CMAKE_END_TEMP_FILE}") + " > ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} -E ${CMAKE_END_TEMP_FILE}") SET(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE - " > ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP -E ${CMAKE_END_TEMP_FILE}") + " > ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP -E ${CMAKE_END_TEMP_FILE}") SET(CMAKE_C_CREATE_ASSEMBLY_SOURCE " ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /FAs /FoNUL /Fa /c ${CMAKE_END_TEMP_FILE}") diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 44d857a..b59e949 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -453,6 +453,9 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS")); cmSystemTools::ReplaceString(flags, "\"", "\\\""); + // Add per-source definitions. + this->AppendDefines(flags, sf->GetProperty("COMPILE_DEFINITIONS"), true); + // Using a map and the full path guarantees that we will always get the same // fileRef object for any given full path. // @@ -1260,12 +1263,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) || (target.GetType() == cmTarget::MODULE_LIBRARY)); - // Add the export symbol definition for shared library objects. - if(const char* exportMacro = target.GetExportMacro()) - { - defFlags += "-D"; - defFlags += exportMacro; - } const char* lang = target.GetLinkerLanguage(this); std::string cflags; if(lang) @@ -1291,12 +1288,28 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, cmSystemTools::ReplaceString(defFlags, "\"", "\\\""); cmSystemTools::ReplaceString(flags, "\"", "\\\""); cmSystemTools::ReplaceString(cflags, "\"", "\\\""); + + // Add preprocessor definitions for this target and configuration. + std::string ppDefs; if(this->XcodeVersion > 15) { - buildSettings->AddAttribute - ("GCC_PREPROCESSOR_DEFINITIONS", - this->CreateString("CMAKE_INTDIR=\\\\\"$(CONFIGURATION)\\\\\"")); + this->AppendDefines(ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)\""); + } + if(const char* exportMacro = target.GetExportMacro()) + { + // Add the export symbol definition for shared library objects. + this->AppendDefines(ppDefs, exportMacro); + } + this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS")); + if(configName) + { + std::string defVarName = cmSystemTools::UpperCase(configName); + defVarName += "_COMPILE_DEFINITIONS"; + this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str())); } + buildSettings->AddAttribute + ("GCC_PREPROCESSOR_DEFINITIONS", this->CreateString(ppDefs.c_str())); + std::string extraLinkOptions; if(target.GetType() == cmTarget::EXECUTABLE) { @@ -2887,3 +2900,64 @@ std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix, } return default_flags; } + +//---------------------------------------------------------------------------- +void cmGlobalXCodeGenerator::AppendDefines(std::string& defs, + const char* defines_list, + bool dflag) +{ + // Skip this if there are no definitions. + if(!defines_list) + { + return; + } + + // Expand the list of definitions. + std::vector defines; + cmSystemTools::ExpandListArgument(defines_list, defines); + + // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions. + // We escape everything as follows: + // - Place each definition in single quotes '' + // - Escape a single quote as \\' + // - Escape a backslash as \\\\ + // Note that in the code below we need one more level of escapes for + // C string syntax in this source file. + const char* sep = defs.empty()? "" : " "; + for(std::vector::const_iterator di = defines.begin(); + di != defines.end(); ++di) + { + // Separate from previous definition. + defs += sep; + sep = " "; + + // Open single quote. + defs += "'"; + + // Add -D flag if requested. + if(dflag) + { + defs += "-D"; + } + + // Escaped definition string. + for(const char* c = di->c_str(); *c; ++c) + { + if(*c == '\'') + { + defs += "\\\\'"; + } + else if(*c == '\\') + { + defs += "\\\\\\\\"; + } + else + { + defs += *c; + } + } + + // Close single quote. + defs += "'"; + } +} diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index aa4f3be..2b289fa 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -173,6 +173,9 @@ private: const char* varNameSuffix, const char* default_flags); + void AppendDefines(std::string& defs, const char* defines_list, + bool dflag = false); + protected: virtual const char* GetInstallTargetName() { return "install"; } virtual const char* GetPackageTargetName() { return "package"; } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 1af2f80..636ee8d 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -856,6 +856,10 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable, return replaceValues.ObjectsQuoted; } } + if(replaceValues.Defines && variable == "DEFINES") + { + return replaceValues.Defines; + } if(replaceValues.TargetPDB ) { if(variable == "TARGET_PDB") @@ -2214,6 +2218,77 @@ void cmLocalGenerator::AppendFlags(std::string& flags, } //---------------------------------------------------------------------------- +void cmLocalGenerator::AppendDefines(std::string& defines, + const char* defines_list) +{ + // Short-circuit if there are no definitions. + if(!defines_list) + { + return; + } + + // Expand the list of definitions. + std::vector defines_vec; + cmSystemTools::ExpandListArgument(defines_list, defines_vec); + + // Short-circuit if there are no definitions. + if(defines_vec.empty()) + { + return; + } + + // Separate from previous definitions with a space. + if(!defines.empty()) + { + defines += " "; + } + + // Add each definition to the command line with appropriate escapes. + const char* dsep = "-D"; + for(std::vector::const_iterator di = defines_vec.begin(); + di != defines_vec.end(); ++di) + { + // Skip unsupported definitions. + if(!this->CheckDefinition(*di)) + { + continue; + } + + // Append the -D + defines += dsep; + + // Append the definition with proper escaping. + if(this->WatcomWMake) + { + // The Watcom compiler does its own command line parsing instead + // of using the windows shell rules. Definitions are one of + // -DNAME + // -DNAME= + // -DNAME="c-string with spaces and other characters(?@#$)" + // + // Watcom will properly parse each of these cases from the + // command line without any escapes. However we still have to + // get the '$' and '#' characters through WMake as '$$' and + // '$#'. + for(const char* c = di->c_str(); *c; ++c) + { + if(*c == '$' || *c == '#') + { + defines += '$'; + } + defines += *c; + } + } + else + { + // Make the definition appear properly on the command line. + defines += this->EscapeForShell(di->c_str(), true); + } + dsep = " -D"; + } +} + +//---------------------------------------------------------------------------- std::string cmLocalGenerator::ConstructComment(const cmCustomCommand& cc, const char* default_comment) @@ -2963,3 +3038,45 @@ bool cmLocalGenerator::NeedBackwardsCompatibility(unsigned int major, return (actual_compat && actual_compat <= CMake_VERSION_ENCODE(major, minor, patch)); } + +//---------------------------------------------------------------------------- +bool cmLocalGenerator::CheckDefinition(std::string const& define) const +{ + // Many compilers do not support -DNAME(arg)=sdf so we disable it. + bool function_style = false; + for(const char* c = define.c_str(); *c && *c != '='; ++c) + { + if(*c == '(') + { + function_style = true; + break; + } + } + if(function_style) + { + cmOStringStream e; + e << "WARNING: Function-style preprocessor definitions may not be " + << "passed on the compiler command line because many compilers " + << "do not support it.\n" + << "CMake is dropping a preprocessor definition: " << define << "\n" + << "Consider defining the macro in a (configured) header file.\n"; + cmSystemTools::Message(e.str().c_str()); + return false; + } + + // Many compilers do not support # in the value so we disable it. + if(define.find_first_of("#") != define.npos) + { + cmOStringStream e; + e << "WARNING: Peprocessor definitions containing '#' may not be " + << "passed on the compiler command line because many compilers " + << "do not support it.\n" + << "CMake is dropping a preprocessor definition: " << define << "\n" + << "Consider defining the macro in a (configured) header file.\n"; + cmSystemTools::Message(e.str().c_str()); + return false; + } + + // Assume it is supported. + return true; +} diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 12e7451..23458c9 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -139,6 +139,12 @@ public: ///! Get the include flags for the current makefile and language const char* GetIncludeFlags(const char* lang); + /** + * Encode a list of preprocessor definitions for the compiler + * command line. + */ + void AppendDefines(std::string& defines, const char* defines_list); + /** Translate a dependency as given in CMake code to the name to appear in a generated build file. If the given name is that of a CMake target it will be transformed to the real output @@ -207,6 +213,7 @@ public: const char* TargetInstallNameDir; const char* LinkFlags; const char* LanguageCompileFlags; + const char* Defines; }; /** Escape the given string to be used as a command line argument in @@ -324,6 +331,10 @@ protected: std::string FindRelativePathTopBinary(); void SetupPathConversions(); + /** Check whether the native build system supports the given + definition. Issues a warning. */ + virtual bool CheckDefinition(std::string const& define) const; + cmMakefile *Makefile; cmGlobalGenerator *GlobalGenerator; // members used for relative path function ConvertToMakefilePath diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 1613b82..adabd0a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -338,17 +338,9 @@ cmLocalUnixMakefileGenerator3 // Add a rule to drive the rule below. std::vector depends; depends.push_back(output); - std::vector commands; - cmGlobalUnixMakefileGenerator3* gg = - static_cast(this->GlobalGenerator); - std::string emptyCommand = gg->GetEmptyRuleHackCommand(); - if(!emptyCommand.empty()) - { - commands.push_back(emptyCommand); - } - + std::vector no_commands; this->WriteMakeRule(ruleFileStream, 0, - outNoExt.c_str(), depends, commands, true, true); + outNoExt.c_str(), depends, no_commands, true, true); inHelp = false; } diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index dda7e60..0f67bf1 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -413,6 +413,29 @@ void cmLocalVisualStudio6Generator compileFlags += cflags; } + // Add per-source and per-configuration preprocessor definitions. + std::map cdmap; + this->AppendDefines(compileFlags, + (*sf)->GetProperty("COMPILE_DEFINITIONS")); + if(const char* cdefs = (*sf)->GetProperty("DEBUG_COMPILE_DEFINITIONS")) + { + this->AppendDefines(cdmap["DEBUG"], cdefs); + } + if(const char* cdefs = (*sf)->GetProperty("RELEASE_COMPILE_DEFINITIONS")) + { + this->AppendDefines(cdmap["RELEASE"], cdefs); + } + if(const char* cdefs = + (*sf)->GetProperty("MINSIZEREL_COMPILE_DEFINITIONS")) + { + this->AppendDefines(cdmap["MINSIZEREL"], cdefs); + } + if(const char* cdefs = + (*sf)->GetProperty("RELWITHDEBINFO_COMPILE_DEFINITIONS")) + { + this->AppendDefines(cdmap["RELWITHDEBINFO"], cdefs); + } + const char* lang = this->GetSourceFileLanguage(*(*sf)); if(lang) { @@ -464,12 +487,14 @@ void cmLocalVisualStudio6Generator this->WriteCustomRule(fout, source.c_str(), *command, flags); } else if(!compileFlags.empty() || !objectNameDir.empty() || - excludedFromBuild) + excludedFromBuild || !cdmap.empty()) { for(std::vector::iterator i = this->Configurations.begin(); i != this->Configurations.end(); ++i) { + // Strip the subdirectory name out of the configuration name. + std::string config = this->GetConfigName(*i); if (i == this->Configurations.begin()) { fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl; @@ -486,11 +511,14 @@ void cmLocalVisualStudio6Generator { fout << "\n# ADD CPP " << compileFlags << "\n\n"; } + std::map::iterator cdi = + cdmap.find(cmSystemTools::UpperCase(config)); + if(cdi != cdmap.end() && !cdi->second.empty()) + { + fout << "\n# ADD CPP " << cdi->second << "\n\n"; + } if(!objectNameDir.empty()) { - // Strip the subdirectory name out of the configuration name. - std::string config = this->GetConfigName(*i); - // Setup an alternate object file directory. fout << "\n# PROP Intermediate_Dir \"" << config << "/" << objectNameDir << "\"\n\n"; @@ -1474,6 +1502,19 @@ void cmLocalVisualStudio6Generator flags += targetFlags; } + // Add per-target and per-configuration preprocessor definitions. + this->AppendDefines(flags, target.GetProperty("COMPILE_DEFINITIONS")); + this->AppendDefines(flagsDebug, + target.GetProperty("DEBUG_COMPILE_DEFINITIONS")); + this->AppendDefines(flagsRelease, + target.GetProperty("RELEASE_COMPILE_DEFINITIONS")); + this->AppendDefines + (flagsMinSize, + target.GetProperty("MINSIZEREL_COMPILE_DEFINITIONS")); + this->AppendDefines + (flagsDebugRel, + target.GetProperty("RELWITHDEBINFO_COMPILE_DEFINITIONS")); + // The template files have CXX FLAGS in them, that need to be replaced. // There are not separate CXX and C template files, so we use the same // variable names. The previous code sets up flags* variables to contain @@ -1584,3 +1625,30 @@ cmLocalVisualStudio6Generator config = config.substr(0, config.size()-1); return config; } + +//---------------------------------------------------------------------------- +bool +cmLocalVisualStudio6Generator +::CheckDefinition(std::string const& define) const +{ + // Perform the standard check first. + if(!this->cmLocalGenerator::CheckDefinition(define)) + { + return false; + } + + // Now do the VS6-specific check. + if(define.find_first_of("=") != define.npos) + { + cmOStringStream e; + e << "WARNING: The VS6 IDE does not support preprocessor definitions " + << "with values.\n" + << "CMake is dropping a preprocessor definition: " << define << "\n" + << "Consider defining the macro in a (configured) header file.\n"; + cmSystemTools::Message(e.str().c_str()); + return false; + } + + // Assume it is supported. + return true; +} diff --git a/Source/cmLocalVisualStudio6Generator.h b/Source/cmLocalVisualStudio6Generator.h index 85dea08..e361a18 100644 --- a/Source/cmLocalVisualStudio6Generator.h +++ b/Source/cmLocalVisualStudio6Generator.h @@ -103,6 +103,9 @@ private: std::vector Configurations; std::string GetConfigName(std::string const& configuration) const; + + // Special definition check for VS6. + virtual bool CheckDefinition(std::string const& define) const; }; #endif diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 51ebcbc..ab3d024 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -384,7 +384,8 @@ public: Compiler, Linker }; - cmLocalVisualStudio7GeneratorOptions(Tool tool, + cmLocalVisualStudio7GeneratorOptions(cmLocalVisualStudio7Generator* lg, + Tool tool, cmVS7FlagTable const* extraTable = 0); // Store options from command line flags. @@ -398,6 +399,7 @@ public: // Store definitions and flags. void AddDefine(const std::string& define); + void AddDefines(const char* defines); void AddFlag(const char* flag, const char* value); // Check for specific options. @@ -413,6 +415,8 @@ public: const char* suffix); private: + cmLocalVisualStudio7Generator* LocalGenerator; + // create a map of xml tags to the values they should have in the output // for example, "BufferSecurityCheck" = "TRUE" // first fill this table with the values for the configuration @@ -423,7 +427,7 @@ private: std::map FlagMap; // Preprocessor definitions. - std::vector Defines; + std::vector Defines; // Unrecognized flags that get no special handling. cmStdString FlagString; @@ -516,14 +520,20 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, flags += targetFlags; } + std::string configUpper = cmSystemTools::UpperCase(configName); + std::string defPropName = configUpper; + defPropName += "_COMPILE_DEFINITIONS"; + // Get preprocessor definitions for this directory. std::string defineFlags = this->Makefile->GetDefineFlags(); // Construct a set of build options for this target. - Options targetOptions(Options::Compiler, this->ExtraFlagTable); + Options targetOptions(this, Options::Compiler, this->ExtraFlagTable); targetOptions.FixExceptionHandlingDefault(); targetOptions.Parse(flags.c_str()); targetOptions.Parse(defineFlags.c_str()); + targetOptions.AddDefines(target.GetProperty("COMPILE_DEFINITIONS")); + targetOptions.AddDefines(target.GetProperty(defPropName.c_str())); targetOptions.SetVerboseMakefile( this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); @@ -703,7 +713,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, extraLinkOptions += " "; extraLinkOptions += targetLinkFlags; } - Options linkOptions(Options::Linker); + Options linkOptions(this, Options::Linker); linkOptions.Parse(extraLinkOptions.c_str()); switch(target.GetType()) { @@ -1027,6 +1037,135 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, this->WriteVCProjFooter(fout); } +struct cmLVS7GFileConfig +{ + std::string ObjectName; + std::string CompileFlags; + std::string CompileDefs; + std::string CompileDefsConfig; + std::string AdditionalDeps; + bool ExcludedFromBuild; +}; + +class cmLocalVisualStudio7GeneratorFCInfo +{ +public: + cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg, + cmTarget& target, + cmSourceFile const& sf, + std::vector* configs, + std::string::size_type dir_len); + std::map FileConfigMap; +}; + +cmLocalVisualStudio7GeneratorFCInfo +::cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg, + cmTarget& target, + cmSourceFile const& sf, + std::vector* configs, + std::string::size_type dir_len) +{ + std::string objectName; + if(lg->NeedObjectName.find(&sf) != lg->NeedObjectName.end()) + { + objectName = lg->GetObjectFileNameWithoutTarget(sf, dir_len); + } + + // Compute per-source, per-config information. + for(std::vector::iterator i = configs->begin(); + i != configs->end(); ++i) + { + std::string configUpper = cmSystemTools::UpperCase(*i); + cmLVS7GFileConfig fc; + bool needfc = false; + if(!objectName.empty()) + { + fc.ObjectName = objectName; + needfc = true; + } + if(const char* cflags = sf.GetProperty("COMPILE_FLAGS")) + { + fc.CompileFlags = cflags; + needfc = true; + } + if(const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) + { + fc.CompileDefs = cdefs; + needfc = true; + } + std::string defPropName = configUpper; + defPropName += "_COMPILE_DEFINITIONS"; + if(const char* ccdefs = sf.GetProperty(defPropName.c_str())) + { + fc.CompileDefsConfig = ccdefs; + needfc = true; + } + + // Check for extra object-file dependencies. + if(const char* deps = sf.GetProperty("OBJECT_DEPENDS")) + { + std::vector depends; + cmSystemTools::ExpandListArgument(deps, depends); + const char* sep = ""; + for(std::vector::iterator j = depends.begin(); + j != depends.end(); ++j) + { + fc.AdditionalDeps += sep; + fc.AdditionalDeps += lg->ConvertToXMLOutputPath(j->c_str()); + sep = ";"; + needfc = true; + } + } + + const char* lang = + lg->GlobalGenerator->GetLanguageFromExtension + (sf.GetExtension().c_str()); + const char* sourceLang = lg->GetSourceFileLanguage(sf); + const char* linkLanguage = target.GetLinkerLanguage + (lg->GetGlobalGenerator()); + bool needForceLang = false; + // source file does not match its extension language + if(lang && sourceLang && strcmp(lang, sourceLang) != 0) + { + needForceLang = true; + lang = sourceLang; + } + // If lang is set, the compiler will generate code automatically. + // If HEADER_FILE_ONLY is set, we must suppress this generation in + // the project file + fc.ExcludedFromBuild = + (lang && sf.GetPropertyAsBool("HEADER_FILE_ONLY")); + if(fc.ExcludedFromBuild) + { + needfc = true; + } + + // if the source file does not match the linker language + // then force c or c++ + if(needForceLang || (linkLanguage && lang + && strcmp(lang, linkLanguage) != 0)) + { + if(strcmp(lang, "CXX") == 0) + { + // force a C++ file type + fc.CompileFlags += " /TP "; + needfc = true; + } + else if(strcmp(lang, "C") == 0) + { + // force to c + fc.CompileFlags += " /TC "; + needfc = true; + } + } + + if(needfc) + { + this->FileConfigMap[*i] = fc; + } + } +} + void cmLocalVisualStudio7Generator ::WriteGroup(const cmSourceGroup *sg, cmTarget target, std::ostream &fout, const char *libName, @@ -1075,76 +1214,8 @@ void cmLocalVisualStudio7Generator sourceFiles.begin(); sf != sourceFiles.end(); ++sf) { std::string source = (*sf)->GetFullPath(); - const cmCustomCommand *command = (*sf)->GetCustomCommand(); - std::string compileFlags; - std::string additionalDeps; - if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end()) - { - objectName = this->GetObjectFileNameWithoutTarget(*(*sf), dir_len); - } - else - { - objectName = ""; - } - // Add per-source flags. - const char* cflags = (*sf)->GetProperty("COMPILE_FLAGS"); - if(cflags) - { - compileFlags += " "; - compileFlags += cflags; - } - const char* lang = - this->GlobalGenerator->GetLanguageFromExtension - ((*sf)->GetExtension().c_str()); - const char* sourceLang = this->GetSourceFileLanguage(*(*sf)); - const char* linkLanguage = target.GetLinkerLanguage - (this->GetGlobalGenerator()); - bool needForceLang = false; - // source file does not match its extension language - if(lang && sourceLang && strcmp(lang, sourceLang) != 0) - { - needForceLang = true; - lang = sourceLang; - } - // If lang is set, the compiler will generate code automatically. - // If HEADER_FILE_ONLY is set, we must suppress this generation in - // the project file - bool excludedFromBuild = - (lang && (*sf)->GetPropertyAsBool("HEADER_FILE_ONLY")); + FCInfo fcinfo(this, target, *(*sf), configs, dir_len); - // if the source file does not match the linker language - // then force c or c++ - if(needForceLang || (linkLanguage && lang - && strcmp(lang, linkLanguage) != 0)) - { - if(strcmp(lang, "CXX") == 0) - { - // force a C++ file type - compileFlags += " /TP "; - } - else if(strcmp(lang, "C") == 0) - { - // force to c - compileFlags += " /TC "; - } - } - // Check for extra object-file dependencies. - const char* deps = (*sf)->GetProperty("OBJECT_DEPENDS"); - if(deps) - { - std::vector depends; - cmSystemTools::ExpandListArgument(deps, depends); - if(!depends.empty()) - { - std::vector::iterator i = depends.begin(); - additionalDeps = this->ConvertToXMLOutputPath(i->c_str()); - for(++i;i != depends.end(); ++i) - { - additionalDeps += ";"; - additionalDeps += this->ConvertToXMLOutputPath(i->c_str()); - } - } - } if (source != libName || target.GetType() == cmTarget::UTILITY || target.GetType() == cmTarget::GLOBAL_TARGET ) { @@ -1153,13 +1224,11 @@ void cmLocalVisualStudio7Generator // Tell MS-Dev what the source is. If the compiler knows how to // build it, then it will. fout << "\t\t\t\tRelativePath=\"" << d << "\">\n"; - if (command) + if(cmCustomCommand const* command = (*sf)->GetCustomCommand()) { - const char* flags = compileFlags.size() ? compileFlags.c_str(): 0; - this->WriteCustomRule(fout, source.c_str(), *command, flags); + this->WriteCustomRule(fout, source.c_str(), *command, fcinfo); } - else if(compileFlags.size() || additionalDeps.length() - || objectName.size() || excludedFromBuild) + else if(!fcinfo.FileConfigMap.empty()) { const char* aCompilerTool = "VCCLCompilerTool"; std::string ext = (*sf)->GetExtension(); @@ -1176,37 +1245,44 @@ void cmLocalVisualStudio7Generator { aCompilerTool = "VCCustomBuildTool"; } - for(std::vector::iterator i = configs->begin(); - i != configs->end(); ++i) + for(std::map::const_iterator + fci = fcinfo.FileConfigMap.begin(); + fci != fcinfo.FileConfigMap.end(); ++fci) { + cmLVS7GFileConfig const& fc = fci->second; fout << "\t\t\t\tfirst << "|" << this->PlatformName << "\""; - if(excludedFromBuild) + if(fc.ExcludedFromBuild) { fout << " ExcludedFromBuild=\"true\""; } fout << ">\n"; fout << "\t\t\t\t\tExtraFlagTable); - fileOptions.Parse(compileFlags.c_str()); + Options fileOptions(this, Options::Compiler, + this->ExtraFlagTable); + fileOptions.Parse(fc.CompileFlags.c_str()); + fileOptions.AddDefines(fc.CompileDefs.c_str()); + fileOptions.AddDefines(fc.CompileDefsConfig.c_str()); fileOptions.OutputAdditionalOptions(fout, "\t\t\t\t\t", "\n"); fileOptions.OutputFlagMap(fout, "\t\t\t\t\t"); fileOptions.OutputPreprocessorDefinitions(fout, "\t\t\t\t\t", "\n"); } - if(additionalDeps.length()) + if(!fc.AdditionalDeps.empty()) { fout << "\t\t\t\t\tAdditionalDependencies=\"" - << additionalDeps.c_str() << "\"\n"; + << fc.AdditionalDeps.c_str() << "\"\n"; } - if(objectName.size()) + if(!fc.ObjectName.empty()) { fout << "\t\t\t\t\tObjectFile=\"$(IntDir)/" - << objectName.c_str() << "\"\n"; + << fc.ObjectName.c_str() << "\"\n"; } fout << "\t\t\t\t\t/>\n" << "\t\t\t\t\n"; @@ -1234,7 +1310,7 @@ void cmLocalVisualStudio7Generator:: WriteCustomRule(std::ostream& fout, const char* source, const cmCustomCommand& command, - const char* compileFlags) + FCInfo& fcinfo) { std::string comment = this->ConstructComment(command); @@ -1246,14 +1322,15 @@ WriteCustomRule(std::ostream& fout, for(i = configs->begin(); i != configs->end(); ++i) { + cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[*i]; fout << "\t\t\t\tPlatformName << "\">\n"; - if(compileFlags) + if(!fc.CompileFlags.empty()) { fout << "\t\t\t\t\tEscapeForXML(compileFlags) << "\"/>\n"; + << this->EscapeForXML(fc.CompileFlags.c_str()) << "\"/>\n"; } std::string script = @@ -1659,9 +1736,10 @@ std::string cmLocalVisualStudio7Generator //---------------------------------------------------------------------------- cmLocalVisualStudio7GeneratorOptions -::cmLocalVisualStudio7GeneratorOptions(Tool tool, +::cmLocalVisualStudio7GeneratorOptions(cmLocalVisualStudio7Generator* lg, + Tool tool, cmVS7FlagTable const* extraTable): - CurrentTool(tool), + LocalGenerator(lg), CurrentTool(tool), DoingDefine(false), FlagTable(0), ExtraFlagTable(extraTable) { // Choose the flag table for the requested tool. @@ -1707,6 +1785,16 @@ void cmLocalVisualStudio7GeneratorOptions::AddDefine(const std::string& def) } //---------------------------------------------------------------------------- +void cmLocalVisualStudio7GeneratorOptions::AddDefines(const char* defines) +{ + if(defines) + { + // Expand the list of definitions. + cmSystemTools::ExpandListArgument(defines, this->Defines); + } +} + +//---------------------------------------------------------------------------- void cmLocalVisualStudio7GeneratorOptions::AddFlag(const char* flag, const char* value) { @@ -1717,7 +1805,7 @@ void cmLocalVisualStudio7GeneratorOptions::AddFlag(const char* flag, bool cmLocalVisualStudio7GeneratorOptions::UsingUnicode() { // Look for the a _UNICODE definition. - for(std::vector::const_iterator di = this->Defines.begin(); + for(std::vector::const_iterator di = this->Defines.begin(); di != this->Defines.end(); ++di) { if(*di == "_UNICODE") @@ -1886,29 +1974,18 @@ cmLocalVisualStudio7GeneratorOptions fout << prefix << "PreprocessorDefinitions=\""; const char* comma = ""; - for(std::vector::const_iterator di = this->Defines.begin(); + for(std::vector::const_iterator di = this->Defines.begin(); di != this->Defines.end(); ++di) { - // Double-quotes in the value of the definition must be escaped - // with a backslash. - std::string define = di->c_str(); - cmSystemTools::ReplaceString(define, "\"", "\\\""); + // Escape the definition for the compiler. + std::string define = + this->LocalGenerator->EscapeForShell(di->c_str(), true); // Escape this flag for the IDE. define = cmLocalVisualStudio7GeneratorEscapeForXML(define.c_str()); - // Write this flag. Quote it if the definition is not - // alphanumeric. - if(define.find_first_not_of( - "-_abcdefghigklmnopqrstuvwxyz1234567890ABCDEFGHIGKLMNOPQRSTUVWXYZ") - != define.npos) - { - fout << comma << """ << define << """; - } - else - { - fout << comma << define; - } + // Store the flag in the project file. + fout << comma << define; comma = ","; } fout << "\"" << suffix; diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 7055fe0..3687289 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -26,6 +26,7 @@ class cmSourceGroup; struct cmVS7FlagTable; class cmLocalVisualStudio7GeneratorOptions; +class cmLocalVisualStudio7GeneratorFCInfo; /** \class cmLocalVisualStudio7Generator * \brief Write Visual Studio .NET project files. @@ -68,6 +69,7 @@ public: { this->ExtraFlagTable = table; } private: typedef cmLocalVisualStudio7GeneratorOptions Options; + typedef cmLocalVisualStudio7GeneratorFCInfo FCInfo; void ReadAndStoreExternalGUID(const char* name, const char* path); std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags, @@ -109,7 +111,7 @@ private: void WriteCustomRule(std::ostream& fout, const char* source, const cmCustomCommand& command, - const char* extraFlags); + FCInfo& fcinfo); void WriteTargetVersionAttribute(std::ostream& fout, cmTarget& target); void WriteGroup(const cmSourceGroup *sg, @@ -117,6 +119,8 @@ private: const char *libName, std::vector *configs); virtual std::string GetTargetDirectory(cmTarget const&) const; + friend class cmLocalVisualStudio7GeneratorFCInfo; + cmVS7FlagTable const* ExtraFlagTable; std::string ModuleDefinitionFile; int Version; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 6c3002e..86c567d 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -254,6 +254,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() { const char *lang = l->c_str(); std::string flags; + std::string defines; bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) || (this->Target->GetType() == cmTarget::MODULE_LIBRARY)); @@ -264,6 +265,15 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() flags += exportMacro; } + // Add preprocessor definitions for this target and configuration. + this->LocalGenerator->AppendDefines + (defines, this->Target->GetProperty("COMPILE_DEFINITIONS")); + std::string defPropName = + cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); + defPropName += "_COMPILE_DEFINITIONS"; + this->LocalGenerator->AppendDefines + (defines, this->Target->GetProperty(defPropName.c_str())); + // Add language-specific flags. this->LocalGenerator ->AddLanguageFlags(flags, lang, @@ -286,6 +296,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() AppendFlags(flags,this->GetFrameworkFlags().c_str()); *this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n"; + *this->FlagFileStream << lang << "_DEFINES = " << defines << "\n\n"; } // Add target-specific flags. @@ -437,6 +448,35 @@ cmMakefileTargetGenerator << "\n"; } + // Add language-specific defines. + std::string defines = "$("; + defines += lang; + defines += "_DEFINES)"; + + // Add source-sepcific preprocessor definitions. + if(const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) + { + this->LocalGenerator->AppendDefines(defines, compile_defs); + *this->FlagFileStream << "# Custom defines: " + << relativeObj << "_DEFINES = " + << compile_defs << "\n" + << "\n"; + } + std::string configUpper = + cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); + std::string defPropName = configUpper; + defPropName += "_COMPILE_DEFINITIONS"; + if(const char* config_compile_defs = + source.GetProperty(defPropName.c_str())) + { + this->LocalGenerator->AppendDefines(defines, config_compile_defs); + *this->FlagFileStream + << "# Custom defines: " + << relativeObj << "_DEFINES_" << configUpper + << " = " << config_compile_defs << "\n" + << "\n"; + } + // Get the output paths for source and object files. std::string sourceFile = source.GetFullPath(); if(this->LocalGenerator->UseRelativePaths) @@ -522,6 +562,7 @@ cmMakefileTargetGenerator std::string objectDir = cmSystemTools::GetFilenamePath(obj); vars.ObjectDir = objectDir.c_str(); vars.Flags = flags.c_str(); + vars.Defines = defines.c_str(); // Expand placeholders in the commands. for(std::vector::iterator i = commands.begin(); @@ -601,7 +642,11 @@ cmMakefileTargetGenerator preprocessCommands.begin(), preprocessCommands.end()); - vars.PreprocessedSource = objI.c_str(); + std::string shellObjI = + this->Convert(objI.c_str(), + cmLocalGenerator::NONE, + cmLocalGenerator::SHELL).c_str(); + vars.PreprocessedSource = shellObjI.c_str(); // Expand placeholders in the commands. for(std::vector::iterator i = commands.begin(); @@ -653,7 +698,11 @@ cmMakefileTargetGenerator assemblyCommands.begin(), assemblyCommands.end()); - vars.AssemblySource = objS.c_str(); + std::string shellObjS = + this->Convert(objS.c_str(), + cmLocalGenerator::NONE, + cmLocalGenerator::SHELL).c_str(); + vars.AssemblySource = shellObjS.c_str(); // Expand placeholders in the commands. for(std::vector::iterator i = commands.begin(); diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index a8f9285..c902111 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -340,7 +340,33 @@ void cmSourceFile::DefineProperties(cmake *cm) ("COMPILE_FLAGS", cmProperty::SOURCE_FILE, "Additional flags to be added when compiling this source file.", "These flags will be added to the list of compile flags when " - "this source file."); + "this source file builds. Use COMPILE_DEFINITIONS to pass additional " + "preprocessor definitions."); + + cm->DefineProperty + ("COMPILE_DEFINITIONS", cmProperty::SOURCE_FILE, + "Preprocessor definitions for compiling this source file.", + "The COMPILE_DEFINITIONS property may be set to a list of preprocessor " + "definitions using the syntax VAR or VAR=value. Function-style " + "definitions are not supported. CMake will automatically escape " + "the value correctly for the native build system (note that CMake " + "language syntax may require escapes to specify some values). " + "This property may be set on a per-configuration basis using the name " + "_COMPILE_DEFINITIONS where is an upper-case name " + "(ex. \"DEBUG_COMPILE_DEFINITIONS\").\n" + "CMake will automatically drop some definitions that " + "are not supported by the native build tool. " + "The VS6 IDE does not support definitions with values " + "(but NMake does). Xcode does not support per-configuration " + "definitions on source files.\n" + "Dislaimer: Most native build tools have poor support for escaping " + "certain values. CMake has work-arounds for many cases but some " + "values may just not be possible to pass correctly. If a value " + "does not seem to be escaped correctly, do not attempt to " + "work-around the problem by adding escape sequences to the value. " + "Your work-around may break in a future version of CMake that " + "has improved escape support. Instead consider defining the macro " + "in a (configured) header file. Then report the limitation."); cm->DefineProperty ("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE, diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 4f0c5ac..016aa1c 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -67,8 +67,32 @@ void cmTarget::DefineProperties(cmake *cm) ("COMPILE_FLAGS", cmProperty::TARGET, "Additional flags to use when compiling this target's sources.", "The COMPILE_FLAGS property sets additional compiler flags used " - "to build sources within the target. It may also be used to pass " - "additional preprocessor definitions."); + "to build sources within the target. Use COMPILE_DEFINITIONS " + "to pass additional preprocessor definitions."); + + cm->DefineProperty + ("COMPILE_DEFINITIONS", cmProperty::TARGET, + "Preprocessor definitions for compiling this target's sources.", + "The COMPILE_DEFINITIONS property may be set to a list of preprocessor " + "definitions using the syntax VAR or VAR=value. Function-style " + "definitions are not supported. CMake will automatically escape " + "the value correctly for the native build system (note that CMake " + "language syntax may require escapes to specify some values). " + "This property may be set on a per-configuration basis using the name " + "_COMPILE_DEFINITIONS where is an upper-case name " + "(ex. \"DEBUG_COMPILE_DEFINITIONS\").\n" + "CMake will automatically drop some definitions that " + "are not supported by the native build tool. " + "The VS6 IDE does not support definitions with values " + "(but NMake does).\n" + "Dislaimer: Most native build tools have poor support for escaping " + "certain values. CMake has work-arounds for many cases but some " + "values may just not be possible to pass correctly. If a value " + "does not seem to be escaped correctly, do not attempt to " + "work-around the problem by adding escape sequences to the value. " + "Your work-around may break in a future version of CMake that " + "has improved escape support. Instead consider defining the macro " + "in a (configured) header file. Then report the limitation."); cm->DefineProperty ("DEFINE_SYMBOL", cmProperty::TARGET, diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 1d2610e..dea7151 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -49,6 +49,7 @@ IF(BUILD_TESTING) ADD_TEST_MACRO(Properties Properties) ADD_TEST_MACRO(Assembler HelloAsm) ADD_TEST_MACRO(SourceGroups SourceGroups) + ADD_TEST_MACRO(Preprocess Preprocess) IF (CMAKE_STRICT) ADD_TEST_MACRO(DocTest DocTest) diff --git a/Tests/Preprocess/CMakeLists.txt b/Tests/Preprocess/CMakeLists.txt new file mode 100644 index 0000000..3631072 --- /dev/null +++ b/Tests/Preprocess/CMakeLists.txt @@ -0,0 +1,181 @@ +project(Preprocess) + +# This test is meant both as a test and as a reference for supported +# syntax on native tool command lines. + +#----------------------------------------------------------------------------- +# Construct a C-string literal to test passing through a definition on +# the command line. We configure the value into a header so it can be +# checked in the executable at runtime. The semicolon is handled +# specially because it needs to be escaped in the COMPILE_DEFINITIONS +# property value to avoid separating definitions but the string value +# must not have it escaped inside the configured header. +set(STRING_EXTRA "") + +if("${CMAKE_GENERATOR}" MATCHES "Make" AND MSVC) + set(NMAKE 1) +endif("${CMAKE_GENERATOR}" MATCHES "Make" AND MSVC) + +if(NOT BORLAND) + # Borland: ; + # The Borland compiler will simply not accept a non-escaped semicolon + # on the command line. If it is escaped \; then the escape character + # shows up in the preprocessing output too. + set(SEMICOLON "\;") +endif(NOT BORLAND) + +if(NOT BORLAND AND NOT WATCOM) + # Borland, WMake: multiple spaces + # The make tool seems to remove extra whitespace from inside + # quoted strings when passing to the compiler. It does not have + # trouble passing to other tools, and the compiler may be directly + # invoked from the command line. + set(STRING_EXTRA "${STRING_EXTRA} ") +endif(NOT BORLAND AND NOT WATCOM) + +if(NOT "${CMAKE_GENERATOR}" MATCHES "Visual Studio") + # VS: , + # Visual Studio will not accept a comma in the value of a definition. + # The comma-separated list of PreprocessorDefinitions in the project + # file seems to be parsed before the content of entries is examined. + set(STRING_EXTRA "${STRING_EXTRA},") +endif(NOT "${CMAKE_GENERATOR}" MATCHES "Visual Studio") + +if(NOT MINGW) + # MinGW: & + # When inside -D"FOO=\"a & b\"" MinGW make wants -D"FOO=\"a "&" b\"" + # but it does not like quoted ampersand elsewhere. + set(STRING_EXTRA "${STRING_EXTRA}&") +endif(NOT MINGW) + +if(NOT MINGW) + # MinGW: | + # When inside -D"FOO=\"a | b\"" MinGW make wants -D"FOO=\"a "|" b\"" + # but it does not like quoted pipe elsewhere. + set(STRING_EXTRA "${STRING_EXTRA}|") +endif(NOT MINGW) + +if(NOT BORLAND AND NOT MINGW AND NOT NMAKE) + # Borland, NMake, MinGW: ^ + # When inside -D"FOO=\"a ^ b\"" they make wants -D"FOO=\"a "^" b\"" + # but do not like quoted carrot elsewhere. In NMake the non-quoted + # syntax works when the flags are not in a make variable. + set(STRING_EXTRA "${STRING_EXTRA}^") +endif(NOT BORLAND AND NOT MINGW AND NOT NMAKE) + +if(NOT BORLAND AND NOT MINGW AND NOT NMAKE) + # Borland, MinGW: < > + # Angle-brackets have funny behavior that is hard to escape. + set(STRING_EXTRA "${STRING_EXTRA}<>") +endif(NOT BORLAND AND NOT MINGW AND NOT NMAKE) + +# General: \" +# Make tools do not reliably accept \\\" syntax: +# - MinGW and MSYS make tools crash with \\\" +# - Borland make actually wants a mis-matched quote \\" +# or $(BACKSLASH)\" where BACKSLASH is a variable set to \\ +# - VS IDE gets confused about the bounds of the definition value \\\" +# - NMake is okay with just \\\" +if(NMAKE OR "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") + set(STRING_EXTRA "${STRING_EXTRA}\\\"") +endif(NMAKE OR "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") + +# General: # +# MSVC will not accept a # in the value of a string definition on the +# command line. The character seems to be simply replaced by an +# equals =. According to "cl -help" definitions may be specified by +# -DMACRO#VALUE as well as -DMACRO=VALUE. It must be implemented by a +# simple search-and-replace. +# +# The Borland compiler will parse both # and \# as just # but the make +# tool seems to want \# sometimes and not others. +# +# Unix make does not like # in variable settings without extra +# escaping. This could probably be fixed but since MSVC does not +# support it and it is not an operator it is not worthwhile. + +# Compose the final test string. +set(STRING_VALUE "hello `~!@$%*)(_+-=}{][:'.?/ ${STRING_EXTRA}world") + +#----------------------------------------------------------------------------- +# Function-style macro command-line support: +# - Borland does not support +# - MSVC does not support +# - Watcom does not support +# - GCC supports + +# Too few platforms support this to bother implementing. +# People can just configure headers with the macros. + +#----------------------------------------------------------------------------- +# Construct a sample expression to pass as a macro definition. + +set(EXPR "x*y+!(x==(y+1*2))*f(x%2)") + +if(NOT WATCOM) + # Watcom does not support - or / because it parses them as options. + set(EXPR "${EXPR}+y/x-x") +endif(NOT WATCOM) + +#----------------------------------------------------------------------------- + +# Inform the test if the debug configuration is getting built. +# The NDEBUG definition takes care of this for release. +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DPREPROCESS_DEBUG") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DPREPROCESS_DEBUG") + +# Inform the test if it built from Xcode or VS6 IDE. +if(XCODE) + set(PREPROCESS_XCODE 1) +endif(XCODE) +if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6") + set(PREPROCESS_VS6 1) + set(VS6 _vs6) +endif("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6") + +# Test old-style definitions. +add_definitions(-DOLD_DEF -DOLD_EXPR=2) + +set(FILE_PATH "${Preprocess_SOURCE_DIR}/file_def.h") +set(TARGET_PATH "${Preprocess_SOURCE_DIR}/target_def.h") + +# Create a list of definition property strings. +set(TARGET_DEFS "TARGET_DEF") +set(FILE_DEFS "FILE_DEF") + +# Add definitions with values. VS6 does not support this. +if(NOT PREPROCESS_VS6) + list(APPEND TARGET_DEFS + "TARGET_STRING=\"${STRING_VALUE}${SEMICOLON}\"" + "TARGET_EXPR=${EXPR}" + "TARGET_PATH=\"${TARGET_PATH}\"" + ) + list(APPEND FILE_DEFS + "FILE_STRING=\"${STRING_VALUE}${SEMICOLON}\"" + "FILE_EXPR=${EXPR}" + "FILE_PATH=\"${FILE_PATH}\"" + ) +endif(NOT PREPROCESS_VS6) + +add_executable(Preprocess preprocess.c preprocess${VS6}.cxx) +set_target_properties(Preprocess PROPERTIES + COMPILE_DEFINITIONS "${TARGET_DEFS}" + DEBUG_COMPILE_DEFINITIONS "TARGET_DEF_DEBUG" + RELEASE_COMPILE_DEFINITIONS "TARGET_DEF_RELEASE" + ) +set_source_files_properties(preprocess.c preprocess${VS6}.cxx PROPERTIES + COMPILE_DEFINITIONS "${FILE_DEFS}" + DEBUG_COMPILE_DEFINITIONS "FILE_DEF_DEBUG" + RELEASE_COMPILE_DEFINITIONS "FILE_DEF_RELEASE" + ) + +# Helper target for running test manually in build tree. +add_custom_target(drive COMMAND Preprocess) + +# Configure the header file with the desired string value. +if(SEMICOLON) + set(STRING_VALUE "${STRING_VALUE};") +endif(SEMICOLON) +configure_file(${Preprocess_SOURCE_DIR}/preprocess.h.in + ${Preprocess_BINARY_DIR}/preprocess.h) +include_directories(${Preprocess_BINARY_DIR}) diff --git a/Tests/Preprocess/file_def.h b/Tests/Preprocess/file_def.h new file mode 100644 index 0000000..fbf8986 --- /dev/null +++ b/Tests/Preprocess/file_def.h @@ -0,0 +1 @@ +#define FILE_PATH_DEF diff --git a/Tests/Preprocess/preprocess.c b/Tests/Preprocess/preprocess.c new file mode 100644 index 0000000..baa18df --- /dev/null +++ b/Tests/Preprocess/preprocess.c @@ -0,0 +1,170 @@ +#include + +#include FILE_PATH +#include TARGET_PATH + +#include +#include + +int check_defines_C(void) +{ + int result = 1; +#ifndef PREPROCESS_VS6 + if(strcmp(FILE_STRING, STRING_VALUE) != 0) + { + fprintf(stderr, + "FILE_STRING has wrong value in C [%s]\n", FILE_STRING); + result = 0; + } + if(strcmp(TARGET_STRING, STRING_VALUE) != 0) + { + fprintf(stderr, + "TARGET_STRING has wrong value in C [%s]\n", TARGET_STRING); + result = 0; + } + { + int x = 2; + int y = 3; + if((FILE_EXPR) != (EXPR)) + { + fprintf(stderr, "FILE_EXPR did not work in C [%s]\n", + TO_STRING(FILE_EXPR)); + result = 0; + } + if((TARGET_EXPR) != (EXPR)) + { + fprintf(stderr, "TARGET_EXPR did not work in C [%s]\n", + TO_STRING(FILE_EXPR)); + result = 0; + } + } +#endif +#ifdef NDEBUG +# ifdef FILE_DEF_DEBUG + { + fprintf(stderr, "FILE_DEF_DEBUG should not be defined in C\n"); + result = 0; + } +# endif +# ifdef TARGET_DEF_DEBUG + { + fprintf(stderr, "TARGET_DEF_DEBUG should not be defined in C\n"); + result = 0; + } +# endif +# ifndef FILE_DEF_RELEASE +# ifndef PREPROCESS_XCODE + { + fprintf(stderr, "FILE_DEF_RELEASE should be defined in C\n"); + result = 0; + } +# endif +# endif +# ifndef TARGET_DEF_RELEASE + { + fprintf(stderr, "TARGET_DEF_RELEASE should be defined in C\n"); + result = 0; + } +# endif +#endif +#ifdef PREPROCESS_DEBUG +# ifndef FILE_DEF_DEBUG +# ifndef PREPROCESS_XCODE + { + fprintf(stderr, "FILE_DEF_DEBUG should be defined in C\n"); + result = 0; + } +# endif +# endif +# ifndef TARGET_DEF_DEBUG + { + fprintf(stderr, "TARGET_DEF_DEBUG should be defined in C\n"); + result = 0; + } +# endif +# ifdef FILE_DEF_RELEASE + { + fprintf(stderr, "FILE_DEF_RELEASE should not be defined in C\n"); + result = 0; + } +# endif +# ifdef TARGET_DEF_RELEASE + { + fprintf(stderr, "TARGET_DEF_RELEASE should not be defined in C\n"); + result = 0; + } +# endif +#endif +#if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG) +# if !defined(FILE_DEF_DEBUG) || !defined(TARGET_DEF_DEBUG) +# ifndef PREPROCESS_XCODE + { + fprintf(stderr, + "FILE_DEF_DEBUG and TARGET_DEF_DEBUG inconsistent in C\n"); + result = 0; + } +# endif +# endif +# if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE) + { + fprintf(stderr, "DEBUG and RELEASE definitions inconsistent in C\n"); + result = 0; + } +# endif +#endif +#if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE) +# if !defined(FILE_DEF_RELEASE) || !defined(TARGET_DEF_RELEASE) +# ifndef PREPROCESS_XCODE + { + fprintf(stderr, + "FILE_DEF_RELEASE and TARGET_DEF_RELEASE inconsistent in C\n"); + result = 0; + } +# endif +# endif +# if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG) + { + fprintf(stderr, "RELEASE and DEBUG definitions inconsistent in C\n"); + result = 0; + } +# endif +#endif +#ifndef FILE_PATH_DEF + { + fprintf(stderr, "FILE_PATH_DEF not defined in C\n"); + result = 0; + } +#endif +#ifndef TARGET_PATH_DEF + { + fprintf(stderr, "TARGET_PATH_DEF not defined in C\n"); + result = 0; + } +#endif +#ifndef FILE_DEF + { + fprintf(stderr, "FILE_DEF not defined in C\n"); + result = 0; + } +#endif +#ifndef TARGET_DEF + { + fprintf(stderr, "TARGET_DEF not defined in C\n"); + result = 0; + } +#endif +#ifndef OLD_DEF + { + fprintf(stderr, "OLD_DEF not defined in C\n"); + result = 0; + } +#endif +#if !defined(OLD_EXPR) || OLD_EXPR != 2 + { + fprintf(stderr, "OLD_EXPR id not work in C [%s]\n", + TO_STRING(OLD_EXPR)); + result = 0; + } +#endif + return result; +} diff --git a/Tests/Preprocess/preprocess.cxx b/Tests/Preprocess/preprocess.cxx new file mode 100644 index 0000000..07b7183 --- /dev/null +++ b/Tests/Preprocess/preprocess.cxx @@ -0,0 +1,197 @@ +#include + +#include FILE_PATH +#include TARGET_PATH + +#include +#include + +extern "C" int check_defines_C(void); + +int check_defines_CXX() +{ + int result = 1; +#ifndef PREPROCESS_VS6 + if(strcmp(FILE_STRING, STRING_VALUE) != 0) + { + fprintf(stderr, + "FILE_STRING has wrong value in CXX [%s]\n", FILE_STRING); + result = 0; + } + if(strcmp(TARGET_STRING, STRING_VALUE) != 0) + { + fprintf(stderr, + "TARGET_STRING has wrong value in CXX [%s]\n", TARGET_STRING); + result = 0; + } + { + int x = 2; + int y = 3; + if((FILE_EXPR) != (EXPR)) + { + fprintf(stderr, "FILE_EXPR did not work in CXX [%s]\n", + TO_STRING(FILE_EXPR)); + result = 0; + } + if((TARGET_EXPR) != (EXPR)) + { + fprintf(stderr, "TARGET_EXPR did not work in CXX [%s]\n", + TO_STRING(FILE_EXPR)); + result = 0; + } + } +#endif +#ifdef NDEBUG +# ifdef FILE_DEF_DEBUG + { + fprintf(stderr, "FILE_DEF_DEBUG should not be defined in CXX\n"); + result = 0; + } +# endif +# ifdef TARGET_DEF_DEBUG + { + fprintf(stderr, "TARGET_DEF_DEBUG should not be defined in CXX\n"); + result = 0; + } +# endif +# ifndef FILE_DEF_RELEASE +# ifndef PREPROCESS_XCODE + { + fprintf(stderr, "FILE_DEF_RELEASE should be defined in CXX\n"); + result = 0; + } +# endif +# endif +# ifndef TARGET_DEF_RELEASE + { + fprintf(stderr, "TARGET_DEF_RELEASE should be defined in CXX\n"); + result = 0; + } +# endif +#endif +#ifdef PREPROCESS_DEBUG +# ifndef FILE_DEF_DEBUG +# ifndef PREPROCESS_XCODE + { + fprintf(stderr, "FILE_DEF_DEBUG should be defined in CXX\n"); + result = 0; + } +# endif +# endif +# ifndef TARGET_DEF_DEBUG + { + fprintf(stderr, "TARGET_DEF_DEBUG should be defined in CXX\n"); + result = 0; + } +# endif +# ifdef FILE_DEF_RELEASE + { + fprintf(stderr, "FILE_DEF_RELEASE should not be defined in CXX\n"); + result = 0; + } +# endif +# ifdef TARGET_DEF_RELEASE + { + fprintf(stderr, "TARGET_DEF_RELEASE should not be defined in CXX\n"); + result = 0; + } +# endif +#endif +#if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG) +# if !defined(FILE_DEF_DEBUG) || !defined(TARGET_DEF_DEBUG) +# ifndef PREPROCESS_XCODE + { + fprintf(stderr, + "FILE_DEF_DEBUG and TARGET_DEF_DEBUG inconsistent in CXX\n"); + result = 0; + } +# endif +# endif +# if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE) + { + fprintf(stderr, "DEBUG and RELEASE definitions inconsistent in CXX\n"); + result = 0; + } +# endif +#endif +#if defined(FILE_DEF_RELEASE) || defined(TARGET_DEF_RELEASE) +# if !defined(FILE_DEF_RELEASE) || !defined(TARGET_DEF_RELEASE) +# ifndef PREPROCESS_XCODE + { + fprintf(stderr, + "FILE_DEF_RELEASE and TARGET_DEF_RELEASE inconsistent in CXX\n"); + result = 0; + } +# endif +# endif +# if defined(FILE_DEF_DEBUG) || defined(TARGET_DEF_DEBUG) + { + fprintf(stderr, "RELEASE and DEBUG definitions inconsistent in CXX\n"); + result = 0; + } +# endif +#endif +#ifndef FILE_PATH_DEF + { + fprintf(stderr, "FILE_PATH_DEF not defined in CXX\n"); + result = 0; + } +#endif +#ifndef TARGET_PATH_DEF + { + fprintf(stderr, "TARGET_PATH_DEF not defined in CXX\n"); + result = 0; + } +#endif +#ifndef FILE_DEF + { + fprintf(stderr, "FILE_DEF not defined in CXX\n"); + result = 0; + } +#endif +#ifndef TARGET_DEF + { + fprintf(stderr, "TARGET_DEF not defined in CXX\n"); + result = 0; + } +#endif +#ifndef OLD_DEF + { + fprintf(stderr, "OLD_DEF not defined in CXX\n"); + result = 0; + } +#endif +#if !defined(OLD_EXPR) || OLD_EXPR != 2 + { + fprintf(stderr, "OLD_EXPR id not work in C [%s]\n", + TO_STRING(OLD_EXPR)); + result = 0; + } +#endif + return result; +} + +int main() +{ + int result = 1; + + if(!check_defines_C()) + { + result = 0; + } + + if(!check_defines_CXX()) + { + result = 0; + } + + if(result) + { + printf("All preprocessor definitions are correct.\n"); + return 0; + } + else + { + return 1; + } +} diff --git a/Tests/Preprocess/preprocess.h.in b/Tests/Preprocess/preprocess.h.in new file mode 100644 index 0000000..3e1c7a0 --- /dev/null +++ b/Tests/Preprocess/preprocess.h.in @@ -0,0 +1,16 @@ +/* Define configured macros. */ +#define STRING_VALUE "@STRING_VALUE@" +#define EXPR @EXPR@ +#cmakedefine PREPROCESS_XCODE +#cmakedefine PREPROCESS_VS6 + +#ifdef PREPROCESS_VS6 +# define FILE_PATH "@FILE_PATH@" +# define TARGET_PATH "@TARGET_PATH@" +#endif + +/* Declarations and macros shared by all sources. */ +#define TO_STRING(x) TO_STRING0(x) +#define TO_STRING0(x) #x + +static int f(int i) { return i*3; } diff --git a/Tests/Preprocess/preprocess_vs6.cxx b/Tests/Preprocess/preprocess_vs6.cxx new file mode 100644 index 0000000..9df89f6 --- /dev/null +++ b/Tests/Preprocess/preprocess_vs6.cxx @@ -0,0 +1,3 @@ +// The VS6 IDE does not support object name configuration so we need a +// source file with a different name. Include the real source file. +#include "preprocess.cxx" diff --git a/Tests/Preprocess/target_def.h b/Tests/Preprocess/target_def.h new file mode 100644 index 0000000..f016d5c --- /dev/null +++ b/Tests/Preprocess/target_def.h @@ -0,0 +1 @@ +#define TARGET_PATH_DEF -- cgit v0.12