summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/CMakeCInformation.cmake2
-rw-r--r--Modules/CMakeCXXInformation.cmake2
-rw-r--r--Modules/Platform/AIX.cmake10
-rw-r--r--Modules/Platform/Generic-SDCC-C.cmake2
-rw-r--r--Modules/Platform/QNX.cmake2
-rw-r--r--Modules/Platform/Windows-bcc32.cmake8
-rw-r--r--Modules/Platform/Windows-icl.cmake4
-rw-r--r--Modules/Platform/Windows-wcl386.cmake8
-rw-r--r--Modules/Platform/cl.cmake8
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx92
-rw-r--r--Source/cmGlobalXCodeGenerator.h3
-rw-r--r--Source/cmLocalGenerator.cxx117
-rw-r--r--Source/cmLocalGenerator.h11
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx12
-rw-r--r--Source/cmLocalVisualStudio6Generator.cxx76
-rw-r--r--Source/cmLocalVisualStudio6Generator.h3
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx301
-rw-r--r--Source/cmLocalVisualStudio7Generator.h6
-rw-r--r--Source/cmMakefileTargetGenerator.cxx53
-rw-r--r--Source/cmSourceFile.cxx28
-rw-r--r--Source/cmTarget.cxx28
-rw-r--r--Tests/CMakeLists.txt1
-rw-r--r--Tests/Preprocess/CMakeLists.txt181
-rw-r--r--Tests/Preprocess/file_def.h1
-rw-r--r--Tests/Preprocess/preprocess.c170
-rw-r--r--Tests/Preprocess/preprocess.cxx197
-rw-r--r--Tests/Preprocess/preprocess.h.in16
-rw-r--r--Tests/Preprocess/preprocess_vs6.cxx3
-rw-r--r--Tests/Preprocess/target_def.h1
29 files changed, 1184 insertions, 162 deletions
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
- "<CMAKE_C_COMPILER> <FLAGS> -o <OBJECT> -c <SOURCE>")
+ "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
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
- "<CMAKE_CXX_COMPILER> <FLAGS> -o <OBJECT> -c <SOURCE>")
+ "<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
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 "<CMAKE_C_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
- SET (CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+ SET (CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+ SET (CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
ENDIF(NOT CMAKE_COMPILER_IS_GNUCC)
IF(NOT CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_CXX_COMPILE_OBJECT
- "<CMAKE_CXX_COMPILER> -+ <FLAGS> -o <OBJECT> -c <SOURCE>")
- SET (CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
- SET (CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+ "<CMAKE_CXX_COMPILER> -+ <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+ SET (CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+ SET (CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
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 "<CMAKE_C_COMPILER> <FLAGS> -o <OBJECT> -c <SOURCE>")
+SET(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
# link object files to an executable
SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <OBJECTS> --out-fmt-ihx -o <TARGET> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>")
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
- "<CMAKE_CXX_COMPILER> -x c++ <FLAGS> -o <OBJECT> -c <SOURCE>")
+ "<CMAKE_CXX_COMPILER> -x c++ <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
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 <LINK_F
SET(CMAKE_C_CREATE_STATIC_LIBRARY ${CMAKE_CXX_CREATE_STATIC_LIBRARY})
# compile a C++ file into an object file
+# place <DEFINES> outside the response file because Borland refuses
+# to parse quotes from the response file.
SET(CMAKE_CXX_COMPILE_OBJECT
- "<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE}-DWIN32 -P <FLAGS> -o<OBJECT> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_CXX_COMPILER> <DEFINES> ${CMAKE_START_TEMP_FILE}-DWIN32 -P <FLAGS> -o<OBJECT> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
# compile a C file into an object file
+# place <DEFINES> outside the response file because Borland refuses
+# to parse quotes from the response file.
SET(CMAKE_C_COMPILE_OBJECT
- "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE}-DWIN32 -o<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_C_COMPILER> <DEFINES> ${CMAKE_START_TEMP_FILE}-DWIN32 -o<OBJECT> <FLAGS> -c <SOURCE>${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_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP -DWIN32 /Fo<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /TP -DWIN32 /Fo<OBJECT> <DEFINES> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
# compile a C file into an object file
SET(CMAKE_C_COMPILE_OBJECT
- "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} -DWIN32 /Fo<OBJECT> <FLAGS> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} -DWIN32 /Fo<OBJECT> <DEFINES> <FLAGS> -c <SOURCE>${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_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -fo<OBJECT> -c -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<OBJECT> -c -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
# compile a C file into an object file
SET(CMAKE_C_COMPILE_OBJECT
- "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -fo<OBJECT> -c -cc <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<OBJECT> -c -cc <SOURCE>${CMAKE_END_TEMP_FILE}")
# preprocess a C source file
SET(CMAKE_C_CREATE_PREPROCESSED_SOURCE
- "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -fo<PREPROCESSED_SOURCE> -pl -cc <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<PREPROCESSED_SOURCE> -pl -cc <SOURCE>${CMAKE_END_TEMP_FILE}")
# preprocess a C++ source file
SET(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE
- "<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -fo<PREPROCESSED_SOURCE> -pl -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_WCL_QUIET} <FLAGS> -dWIN32 -d+ <DEFINES> -fo<PREPROCESSED_SOURCE> -pl -cc++ <SOURCE>${CMAKE_END_TEMP_FILE}")
SET(CMAKE_CXX_CREATE_SHARED_MODULE
"wlink ${CMAKE_START_TEMP_FILE} system nt_dll ${CMAKE_WLINK_QUIET} name <TARGET> option caseexact file {<OBJECTS>} <LINK_LIBRARIES> ${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_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /TP /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_CXX_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> /TP /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
# compile a C file into an object file
SET(CMAKE_C_COMPILE_OBJECT
- "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> /Fo<OBJECT> /Fd<TARGET_PDB> -c <SOURCE>${CMAKE_END_TEMP_FILE}")
SET(CMAKE_C_LINK_EXECUTABLE
@@ -48,10 +48,10 @@ SET(CMAKE_CXX_LINK_EXECUTABLE
"<CMAKE_CXX_COMPILER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} <FLAGS> <OBJECTS> /Fe<TARGET> /Fd<TARGET_PDB> -link /implib:<TARGET_IMPLIB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
SET(CMAKE_C_CREATE_PREPROCESSED_SOURCE
- "<CMAKE_C_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> -E <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_C_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> -E <SOURCE>${CMAKE_END_TEMP_FILE}")
SET(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE
- "<CMAKE_CXX_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /TP -E <SOURCE>${CMAKE_END_TEMP_FILE}")
+ "<CMAKE_CXX_COMPILER> > <PREPROCESSED_SOURCE> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> <DEFINES> /TP -E <SOURCE>${CMAKE_END_TEMP_FILE}")
SET(CMAKE_C_CREATE_ASSEMBLY_SOURCE
"<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /FAs /FoNUL /Fa<ASSEMBLY_SOURCE> /c <SOURCE>${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<std::string> 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<std::string>::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<std::string> 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<std::string>::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=<cpp-token>
+ // -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<std::string> depends;
depends.push_back(output);
- std::vector<std::string> commands;
- cmGlobalUnixMakefileGenerator3* gg =
- static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
- std::string emptyCommand = gg->GetEmptyRuleHackCommand();
- if(!emptyCommand.empty())
- {
- commands.push_back(emptyCommand);
- }
-
+ std::vector<std::string> 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<cmStdString, cmStdString> 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<std::string>::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<cmStdString, cmStdString>::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<std::string> 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<cmStdString, cmStdString> FlagMap;
// Preprocessor definitions.
- std::vector<cmStdString> Defines;
+ std::vector<std::string> 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<std::string>* configs,
+ std::string::size_type dir_len);
+ std::map<cmStdString, cmLVS7GFileConfig> FileConfigMap;
+};
+
+cmLocalVisualStudio7GeneratorFCInfo
+::cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
+ cmTarget& target,
+ cmSourceFile const& sf,
+ std::vector<std::string>* 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<std::string>::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<std::string> depends;
+ cmSystemTools::ExpandListArgument(deps, depends);
+ const char* sep = "";
+ for(std::vector<std::string>::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<std::string> depends;
- cmSystemTools::ExpandListArgument(deps, depends);
- if(!depends.empty())
- {
- std::vector<std::string>::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<std::string>::iterator i = configs->begin();
- i != configs->end(); ++i)
+ for(std::map<cmStdString, cmLVS7GFileConfig>::const_iterator
+ fci = fcinfo.FileConfigMap.begin();
+ fci != fcinfo.FileConfigMap.end(); ++fci)
{
+ cmLVS7GFileConfig const& fc = fci->second;
fout << "\t\t\t\t<FileConfiguration\n"
- << "\t\t\t\t\tName=\"" << *i
+ << "\t\t\t\t\tName=\"" << fci->first
<< "|" << this->PlatformName << "\"";
- if(excludedFromBuild)
+ if(fc.ExcludedFromBuild)
{
fout << " ExcludedFromBuild=\"true\"";
}
fout << ">\n";
fout << "\t\t\t\t\t<Tool\n"
<< "\t\t\t\t\tName=\"" << aCompilerTool << "\"\n";
- if(!compileFlags.empty())
+ if(!fc.CompileFlags.empty() ||
+ !fc.CompileDefs.empty() ||
+ !fc.CompileDefsConfig.empty())
{
- Options fileOptions(Options::Compiler, this->ExtraFlagTable);
- 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</FileConfiguration>\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\t<FileConfiguration\n";
fout << "\t\t\t\t\tName=\"" << *i << "|" << this->PlatformName << "\">\n";
- if(compileFlags)
+ if(!fc.CompileFlags.empty())
{
fout << "\t\t\t\t\t<Tool\n"
<< "\t\t\t\t\tName=\"VCCLCompilerTool\"\n"
<< "\t\t\t\t\tAdditionalOptions=\""
- << this->EscapeForXML(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<cmStdString>::const_iterator di = this->Defines.begin();
+ for(std::vector<std::string>::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<cmStdString>::const_iterator di = this->Defines.begin();
+ for(std::vector<std::string>::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 << "&quot;" << define << "&quot;";
- }
- 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<std::string> *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<std::string>::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<std::string>::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<std::string>::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 "
+ "<CONFIG>_COMPILE_DEFINITIONS where <CONFIG> 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 "
+ "<CONFIG>_COMPILE_DEFINITIONS where <CONFIG> 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 <preprocess.h>
+
+#include FILE_PATH
+#include TARGET_PATH
+
+#include <string.h>
+#include <stdio.h>
+
+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 <preprocess.h>
+
+#include FILE_PATH
+#include TARGET_PATH
+
+#include <string.h>
+#include <stdio.h>
+
+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