ENH: Create COMPILE_DEFINITIONS property for targets and source files. Create <config>_COMPILE_DEFINITIONS property as per-configuration version. Add Preprocess test to test the feature. Document limitations on Xcode and VS6 generators.

This commit is contained in:
Brad King 2008-01-14 09:20:58 -05:00
parent 2c42f75522
commit 8262ccfd4e
29 changed files with 1184 additions and 162 deletions

View File

@ -141,7 +141,7 @@ ENDIF(NOT CMAKE_C_CREATE_STATIC_LIBRARY)
# compile a C file into an object file # compile a C file into an object file
IF(NOT CMAKE_C_COMPILE_OBJECT) IF(NOT CMAKE_C_COMPILE_OBJECT)
SET(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) ENDIF(NOT CMAKE_C_COMPILE_OBJECT)
IF(NOT CMAKE_C_LINK_EXECUTABLE) IF(NOT CMAKE_C_LINK_EXECUTABLE)

View File

@ -201,7 +201,7 @@ ENDIF(NOT CMAKE_CXX_CREATE_STATIC_LIBRARY)
# compile a C++ file into an object file # compile a C++ file into an object file
IF(NOT CMAKE_CXX_COMPILE_OBJECT) IF(NOT CMAKE_CXX_COMPILE_OBJECT)
SET(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) ENDIF(NOT CMAKE_CXX_COMPILE_OBJECT)
IF(NOT CMAKE_CXX_LINK_EXECUTABLE) IF(NOT CMAKE_CXX_LINK_EXECUTABLE)

View File

@ -33,15 +33,15 @@ ELSE(CMAKE_COMPILER_IS_GNUCC)
ENDIF(CMAKE_COMPILER_IS_GNUCC) ENDIF(CMAKE_COMPILER_IS_GNUCC)
IF(NOT 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_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
SET (CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>") SET (CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
ENDIF(NOT CMAKE_COMPILER_IS_GNUCC) ENDIF(NOT CMAKE_COMPILER_IS_GNUCC)
IF(NOT CMAKE_COMPILER_IS_GNUCXX) IF(NOT CMAKE_COMPILER_IS_GNUCXX)
SET(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>")
SET (CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_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> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>") SET (CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX) ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX)

View File

@ -38,7 +38,7 @@ IF(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT)
ENDIF(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT) ENDIF(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT)
# compile a C file into an object file # 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 # 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>") SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <OBJECTS> --out-fmt-ihx -o <TARGET> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>")

View File

@ -28,6 +28,6 @@ FOREACH(type SHARED_LIBRARY SHARED_MODULE EXE)
ENDFOREACH(type) ENDFOREACH(type)
# force the language to be c++ since qnx only has gcc and not g++ and c++? # force the language to be c++ since qnx only has gcc and not g++ and c++?
SET(CMAKE_CXX_COMPILE_OBJECT 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) INCLUDE(Platform/UnixPaths)

View File

@ -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}) SET(CMAKE_C_CREATE_STATIC_LIBRARY ${CMAKE_CXX_CREATE_STATIC_LIBRARY})
# compile a C++ file into an object 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_CXX_COMPILE_OBJECT 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 # 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 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 SET(CMAKE_C_LINK_EXECUTABLE

View File

@ -27,11 +27,11 @@ SET(CMAKE_C_CREATE_STATIC_LIBRARY ${CMAKE_CXX_CREATE_STATIC_LIBRARY})
# compile a C++ file into an object file # compile a C++ file into an object file
SET(CMAKE_CXX_COMPILE_OBJECT 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 # compile a C file into an object file
SET(CMAKE_C_COMPILE_OBJECT 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 SET(CMAKE_C_LINK_EXECUTABLE

View File

@ -36,19 +36,19 @@ SET(CMAKE_CXX_LINK_EXECUTABLE ${CMAKE_C_LINK_EXECUTABLE})
# compile a C++ file into an object file # compile a C++ file into an object file
SET(CMAKE_CXX_COMPILE_OBJECT 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 # compile a C file into an object file
SET(CMAKE_C_COMPILE_OBJECT 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 # preprocess a C source file
SET(CMAKE_C_CREATE_PREPROCESSED_SOURCE 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 # preprocess a C++ source file
SET(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE 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 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}") "wlink ${CMAKE_START_TEMP_FILE} system nt_dll ${CMAKE_WLINK_QUIET} name <TARGET> option caseexact file {<OBJECTS>} <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")

View File

@ -34,11 +34,11 @@ SET(CMAKE_C_CREATE_STATIC_LIBRARY "${CMAKE_CXX_CREATE_STATIC_LIBRARY}")
# compile a C++ file into an object file # compile a C++ file into an object file
SET(CMAKE_CXX_COMPILE_OBJECT 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 # compile a C file into an object file
SET(CMAKE_C_COMPILE_OBJECT 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 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}") "<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 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 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 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}") "<CMAKE_C_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} <FLAGS> /FAs /FoNUL /Fa<ASSEMBLY_SOURCE> /c <SOURCE>${CMAKE_END_TEMP_FILE}")

View File

@ -453,6 +453,9 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS")); lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
cmSystemTools::ReplaceString(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 // Using a map and the full path guarantees that we will always get the same
// fileRef object for any given full path. // fileRef object for any given full path.
// //
@ -1260,12 +1263,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) || bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
(target.GetType() == cmTarget::MODULE_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); const char* lang = target.GetLinkerLanguage(this);
std::string cflags; std::string cflags;
if(lang) if(lang)
@ -1291,12 +1288,28 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
cmSystemTools::ReplaceString(defFlags, "\"", "\\\""); cmSystemTools::ReplaceString(defFlags, "\"", "\\\"");
cmSystemTools::ReplaceString(flags, "\"", "\\\""); cmSystemTools::ReplaceString(flags, "\"", "\\\"");
cmSystemTools::ReplaceString(cflags, "\"", "\\\""); cmSystemTools::ReplaceString(cflags, "\"", "\\\"");
// Add preprocessor definitions for this target and configuration.
std::string ppDefs;
if(this->XcodeVersion > 15) if(this->XcodeVersion > 15)
{ {
buildSettings->AddAttribute this->AppendDefines(ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)\"");
("GCC_PREPROCESSOR_DEFINITIONS",
this->CreateString("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; std::string extraLinkOptions;
if(target.GetType() == cmTarget::EXECUTABLE) if(target.GetType() == cmTarget::EXECUTABLE)
{ {
@ -2887,3 +2900,64 @@ std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix,
} }
return default_flags; 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 += "'";
}
}

View File

@ -173,6 +173,9 @@ private:
const char* varNameSuffix, const char* varNameSuffix,
const char* default_flags); const char* default_flags);
void AppendDefines(std::string& defs, const char* defines_list,
bool dflag = false);
protected: protected:
virtual const char* GetInstallTargetName() { return "install"; } virtual const char* GetInstallTargetName() { return "install"; }
virtual const char* GetPackageTargetName() { return "package"; } virtual const char* GetPackageTargetName() { return "package"; }

View File

@ -856,6 +856,10 @@ cmLocalGenerator::ExpandRuleVariable(std::string const& variable,
return replaceValues.ObjectsQuoted; return replaceValues.ObjectsQuoted;
} }
} }
if(replaceValues.Defines && variable == "DEFINES")
{
return replaceValues.Defines;
}
if(replaceValues.TargetPDB ) if(replaceValues.TargetPDB )
{ {
if(variable == "TARGET_PDB") if(variable == "TARGET_PDB")
@ -2213,6 +2217,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 std::string
cmLocalGenerator::ConstructComment(const cmCustomCommand& cc, cmLocalGenerator::ConstructComment(const cmCustomCommand& cc,
@ -2963,3 +3038,45 @@ bool cmLocalGenerator::NeedBackwardsCompatibility(unsigned int major,
return (actual_compat && return (actual_compat &&
actual_compat <= CMake_VERSION_ENCODE(major, minor, patch)); 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;
}

View File

@ -139,6 +139,12 @@ public:
///! Get the include flags for the current makefile and language ///! Get the include flags for the current makefile and language
const char* GetIncludeFlags(const char* lang); 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 /** 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 appear in a generated build file. If the given name is that of
a CMake target it will be transformed to the real output a CMake target it will be transformed to the real output
@ -207,6 +213,7 @@ public:
const char* TargetInstallNameDir; const char* TargetInstallNameDir;
const char* LinkFlags; const char* LinkFlags;
const char* LanguageCompileFlags; const char* LanguageCompileFlags;
const char* Defines;
}; };
/** Escape the given string to be used as a command line argument in /** Escape the given string to be used as a command line argument in
@ -324,6 +331,10 @@ protected:
std::string FindRelativePathTopBinary(); std::string FindRelativePathTopBinary();
void SetupPathConversions(); 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; cmMakefile *Makefile;
cmGlobalGenerator *GlobalGenerator; cmGlobalGenerator *GlobalGenerator;
// members used for relative path function ConvertToMakefilePath // members used for relative path function ConvertToMakefilePath

View File

@ -338,17 +338,9 @@ cmLocalUnixMakefileGenerator3
// Add a rule to drive the rule below. // Add a rule to drive the rule below.
std::vector<std::string> depends; std::vector<std::string> depends;
depends.push_back(output); depends.push_back(output);
std::vector<std::string> commands; std::vector<std::string> no_commands;
cmGlobalUnixMakefileGenerator3* gg =
static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
std::string emptyCommand = gg->GetEmptyRuleHackCommand();
if(!emptyCommand.empty())
{
commands.push_back(emptyCommand);
}
this->WriteMakeRule(ruleFileStream, 0, this->WriteMakeRule(ruleFileStream, 0,
outNoExt.c_str(), depends, commands, true, true); outNoExt.c_str(), depends, no_commands, true, true);
inHelp = false; inHelp = false;
} }

View File

@ -413,6 +413,29 @@ void cmLocalVisualStudio6Generator
compileFlags += cflags; 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)); const char* lang = this->GetSourceFileLanguage(*(*sf));
if(lang) if(lang)
{ {
@ -464,12 +487,14 @@ void cmLocalVisualStudio6Generator
this->WriteCustomRule(fout, source.c_str(), *command, flags); this->WriteCustomRule(fout, source.c_str(), *command, flags);
} }
else if(!compileFlags.empty() || !objectNameDir.empty() || else if(!compileFlags.empty() || !objectNameDir.empty() ||
excludedFromBuild) excludedFromBuild || !cdmap.empty())
{ {
for(std::vector<std::string>::iterator i for(std::vector<std::string>::iterator i
= this->Configurations.begin(); = this->Configurations.begin();
i != this->Configurations.end(); ++i) 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()) if (i == this->Configurations.begin())
{ {
fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl; fout << "!IF \"$(CFG)\" == " << i->c_str() << std::endl;
@ -486,11 +511,14 @@ void cmLocalVisualStudio6Generator
{ {
fout << "\n# ADD CPP " << compileFlags << "\n\n"; 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()) if(!objectNameDir.empty())
{ {
// Strip the subdirectory name out of the configuration name.
std::string config = this->GetConfigName(*i);
// Setup an alternate object file directory. // Setup an alternate object file directory.
fout << "\n# PROP Intermediate_Dir \"" fout << "\n# PROP Intermediate_Dir \""
<< config << "/" << objectNameDir << "\"\n\n"; << config << "/" << objectNameDir << "\"\n\n";
@ -1474,6 +1502,19 @@ void cmLocalVisualStudio6Generator
flags += targetFlags; 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. // 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 // 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 // variable names. The previous code sets up flags* variables to contain
@ -1584,3 +1625,30 @@ cmLocalVisualStudio6Generator
config = config.substr(0, config.size()-1); config = config.substr(0, config.size()-1);
return config; 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;
}

View File

@ -103,6 +103,9 @@ private:
std::vector<std::string> Configurations; std::vector<std::string> Configurations;
std::string GetConfigName(std::string const& configuration) const; std::string GetConfigName(std::string const& configuration) const;
// Special definition check for VS6.
virtual bool CheckDefinition(std::string const& define) const;
}; };
#endif #endif

View File

@ -384,7 +384,8 @@ public:
Compiler, Compiler,
Linker Linker
}; };
cmLocalVisualStudio7GeneratorOptions(Tool tool, cmLocalVisualStudio7GeneratorOptions(cmLocalVisualStudio7Generator* lg,
Tool tool,
cmVS7FlagTable const* extraTable = 0); cmVS7FlagTable const* extraTable = 0);
// Store options from command line flags. // Store options from command line flags.
@ -398,6 +399,7 @@ public:
// Store definitions and flags. // Store definitions and flags.
void AddDefine(const std::string& define); void AddDefine(const std::string& define);
void AddDefines(const char* defines);
void AddFlag(const char* flag, const char* value); void AddFlag(const char* flag, const char* value);
// Check for specific options. // Check for specific options.
@ -413,6 +415,8 @@ public:
const char* suffix); const char* suffix);
private: private:
cmLocalVisualStudio7Generator* LocalGenerator;
// create a map of xml tags to the values they should have in the output // create a map of xml tags to the values they should have in the output
// for example, "BufferSecurityCheck" = "TRUE" // for example, "BufferSecurityCheck" = "TRUE"
// first fill this table with the values for the configuration // first fill this table with the values for the configuration
@ -423,7 +427,7 @@ private:
std::map<cmStdString, cmStdString> FlagMap; std::map<cmStdString, cmStdString> FlagMap;
// Preprocessor definitions. // Preprocessor definitions.
std::vector<cmStdString> Defines; std::vector<std::string> Defines;
// Unrecognized flags that get no special handling. // Unrecognized flags that get no special handling.
cmStdString FlagString; cmStdString FlagString;
@ -516,14 +520,20 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
flags += targetFlags; flags += targetFlags;
} }
std::string configUpper = cmSystemTools::UpperCase(configName);
std::string defPropName = configUpper;
defPropName += "_COMPILE_DEFINITIONS";
// Get preprocessor definitions for this directory. // Get preprocessor definitions for this directory.
std::string defineFlags = this->Makefile->GetDefineFlags(); std::string defineFlags = this->Makefile->GetDefineFlags();
// Construct a set of build options for this target. // 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.FixExceptionHandlingDefault();
targetOptions.Parse(flags.c_str()); targetOptions.Parse(flags.c_str());
targetOptions.Parse(defineFlags.c_str()); targetOptions.Parse(defineFlags.c_str());
targetOptions.AddDefines(target.GetProperty("COMPILE_DEFINITIONS"));
targetOptions.AddDefines(target.GetProperty(defPropName.c_str()));
targetOptions.SetVerboseMakefile( targetOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")); this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
@ -703,7 +713,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
extraLinkOptions += " "; extraLinkOptions += " ";
extraLinkOptions += targetLinkFlags; extraLinkOptions += targetLinkFlags;
} }
Options linkOptions(Options::Linker); Options linkOptions(this, Options::Linker);
linkOptions.Parse(extraLinkOptions.c_str()); linkOptions.Parse(extraLinkOptions.c_str());
switch(target.GetType()) switch(target.GetType())
{ {
@ -1027,6 +1037,135 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
this->WriteVCProjFooter(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 void cmLocalVisualStudio7Generator
::WriteGroup(const cmSourceGroup *sg, cmTarget target, ::WriteGroup(const cmSourceGroup *sg, cmTarget target,
std::ostream &fout, const char *libName, std::ostream &fout, const char *libName,
@ -1075,76 +1214,8 @@ void cmLocalVisualStudio7Generator
sourceFiles.begin(); sf != sourceFiles.end(); ++sf) sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
{ {
std::string source = (*sf)->GetFullPath(); std::string source = (*sf)->GetFullPath();
const cmCustomCommand *command = (*sf)->GetCustomCommand(); FCInfo fcinfo(this, target, *(*sf), configs, dir_len);
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"));
// 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 || if (source != libName || target.GetType() == cmTarget::UTILITY ||
target.GetType() == cmTarget::GLOBAL_TARGET ) target.GetType() == cmTarget::GLOBAL_TARGET )
{ {
@ -1153,13 +1224,11 @@ void cmLocalVisualStudio7Generator
// Tell MS-Dev what the source is. If the compiler knows how to // Tell MS-Dev what the source is. If the compiler knows how to
// build it, then it will. // build it, then it will.
fout << "\t\t\t\tRelativePath=\"" << d << "\">\n"; 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, fcinfo);
this->WriteCustomRule(fout, source.c_str(), *command, flags);
} }
else if(compileFlags.size() || additionalDeps.length() else if(!fcinfo.FileConfigMap.empty())
|| objectName.size() || excludedFromBuild)
{ {
const char* aCompilerTool = "VCCLCompilerTool"; const char* aCompilerTool = "VCCLCompilerTool";
std::string ext = (*sf)->GetExtension(); std::string ext = (*sf)->GetExtension();
@ -1176,37 +1245,44 @@ void cmLocalVisualStudio7Generator
{ {
aCompilerTool = "VCCustomBuildTool"; aCompilerTool = "VCCustomBuildTool";
} }
for(std::vector<std::string>::iterator i = configs->begin(); for(std::map<cmStdString, cmLVS7GFileConfig>::const_iterator
i != configs->end(); ++i) fci = fcinfo.FileConfigMap.begin();
fci != fcinfo.FileConfigMap.end(); ++fci)
{ {
cmLVS7GFileConfig const& fc = fci->second;
fout << "\t\t\t\t<FileConfiguration\n" fout << "\t\t\t\t<FileConfiguration\n"
<< "\t\t\t\t\tName=\"" << *i << "\t\t\t\t\tName=\"" << fci->first
<< "|" << this->PlatformName << "\""; << "|" << this->PlatformName << "\"";
if(excludedFromBuild) if(fc.ExcludedFromBuild)
{ {
fout << " ExcludedFromBuild=\"true\""; fout << " ExcludedFromBuild=\"true\"";
} }
fout << ">\n"; fout << ">\n";
fout << "\t\t\t\t\t<Tool\n" fout << "\t\t\t\t\t<Tool\n"
<< "\t\t\t\t\tName=\"" << aCompilerTool << "\"\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); Options fileOptions(this, Options::Compiler,
fileOptions.Parse(compileFlags.c_str()); 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.OutputAdditionalOptions(fout, "\t\t\t\t\t", "\n");
fileOptions.OutputFlagMap(fout, "\t\t\t\t\t"); fileOptions.OutputFlagMap(fout, "\t\t\t\t\t");
fileOptions.OutputPreprocessorDefinitions(fout, fileOptions.OutputPreprocessorDefinitions(fout,
"\t\t\t\t\t", "\n"); "\t\t\t\t\t", "\n");
} }
if(additionalDeps.length()) if(!fc.AdditionalDeps.empty())
{ {
fout << "\t\t\t\t\tAdditionalDependencies=\"" 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)/" fout << "\t\t\t\t\tObjectFile=\"$(IntDir)/"
<< objectName.c_str() << "\"\n"; << fc.ObjectName.c_str() << "\"\n";
} }
fout << "\t\t\t\t\t/>\n" fout << "\t\t\t\t\t/>\n"
<< "\t\t\t\t</FileConfiguration>\n"; << "\t\t\t\t</FileConfiguration>\n";
@ -1234,7 +1310,7 @@ void cmLocalVisualStudio7Generator::
WriteCustomRule(std::ostream& fout, WriteCustomRule(std::ostream& fout,
const char* source, const char* source,
const cmCustomCommand& command, const cmCustomCommand& command,
const char* compileFlags) FCInfo& fcinfo)
{ {
std::string comment = this->ConstructComment(command); std::string comment = this->ConstructComment(command);
@ -1246,14 +1322,15 @@ WriteCustomRule(std::ostream& fout,
for(i = configs->begin(); i != configs->end(); ++i) 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<FileConfiguration\n";
fout << "\t\t\t\t\tName=\"" << *i << "|" << this->PlatformName << "\">\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" fout << "\t\t\t\t\t<Tool\n"
<< "\t\t\t\t\tName=\"VCCLCompilerTool\"\n" << "\t\t\t\t\tName=\"VCCLCompilerTool\"\n"
<< "\t\t\t\t\tAdditionalOptions=\"" << "\t\t\t\t\tAdditionalOptions=\""
<< this->EscapeForXML(compileFlags) << "\"/>\n"; << this->EscapeForXML(fc.CompileFlags.c_str()) << "\"/>\n";
} }
std::string script = std::string script =
@ -1659,9 +1736,10 @@ std::string cmLocalVisualStudio7Generator
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmLocalVisualStudio7GeneratorOptions cmLocalVisualStudio7GeneratorOptions
::cmLocalVisualStudio7GeneratorOptions(Tool tool, ::cmLocalVisualStudio7GeneratorOptions(cmLocalVisualStudio7Generator* lg,
Tool tool,
cmVS7FlagTable const* extraTable): cmVS7FlagTable const* extraTable):
CurrentTool(tool), LocalGenerator(lg), CurrentTool(tool),
DoingDefine(false), FlagTable(0), ExtraFlagTable(extraTable) DoingDefine(false), FlagTable(0), ExtraFlagTable(extraTable)
{ {
// Choose the flag table for the requested tool. // Choose the flag table for the requested tool.
@ -1706,6 +1784,16 @@ void cmLocalVisualStudio7GeneratorOptions::AddDefine(const std::string& def)
this->Defines.push_back(def); this->Defines.push_back(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, void cmLocalVisualStudio7GeneratorOptions::AddFlag(const char* flag,
const char* value) const char* value)
@ -1717,7 +1805,7 @@ void cmLocalVisualStudio7GeneratorOptions::AddFlag(const char* flag,
bool cmLocalVisualStudio7GeneratorOptions::UsingUnicode() bool cmLocalVisualStudio7GeneratorOptions::UsingUnicode()
{ {
// Look for the a _UNICODE definition. // 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) di != this->Defines.end(); ++di)
{ {
if(*di == "_UNICODE") if(*di == "_UNICODE")
@ -1886,29 +1974,18 @@ cmLocalVisualStudio7GeneratorOptions
fout << prefix << "PreprocessorDefinitions=\""; fout << prefix << "PreprocessorDefinitions=\"";
const char* comma = ""; 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) di != this->Defines.end(); ++di)
{ {
// Double-quotes in the value of the definition must be escaped // Escape the definition for the compiler.
// with a backslash. std::string define =
std::string define = di->c_str(); this->LocalGenerator->EscapeForShell(di->c_str(), true);
cmSystemTools::ReplaceString(define, "\"", "\\\"");
// Escape this flag for the IDE. // Escape this flag for the IDE.
define = cmLocalVisualStudio7GeneratorEscapeForXML(define.c_str()); define = cmLocalVisualStudio7GeneratorEscapeForXML(define.c_str());
// Write this flag. Quote it if the definition is not // Store the flag in the project file.
// alphanumeric.
if(define.find_first_not_of(
"-_abcdefghigklmnopqrstuvwxyz1234567890ABCDEFGHIGKLMNOPQRSTUVWXYZ")
!= define.npos)
{
fout << comma << "&quot;" << define << "&quot;";
}
else
{
fout << comma << define; fout << comma << define;
}
comma = ","; comma = ",";
} }
fout << "\"" << suffix; fout << "\"" << suffix;

View File

@ -26,6 +26,7 @@ class cmSourceGroup;
struct cmVS7FlagTable; struct cmVS7FlagTable;
class cmLocalVisualStudio7GeneratorOptions; class cmLocalVisualStudio7GeneratorOptions;
class cmLocalVisualStudio7GeneratorFCInfo;
/** \class cmLocalVisualStudio7Generator /** \class cmLocalVisualStudio7Generator
* \brief Write Visual Studio .NET project files. * \brief Write Visual Studio .NET project files.
@ -68,6 +69,7 @@ public:
{ this->ExtraFlagTable = table; } { this->ExtraFlagTable = table; }
private: private:
typedef cmLocalVisualStudio7GeneratorOptions Options; typedef cmLocalVisualStudio7GeneratorOptions Options;
typedef cmLocalVisualStudio7GeneratorFCInfo FCInfo;
void ReadAndStoreExternalGUID(const char* name, void ReadAndStoreExternalGUID(const char* name,
const char* path); const char* path);
std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags, std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags,
@ -109,7 +111,7 @@ private:
void WriteCustomRule(std::ostream& fout, void WriteCustomRule(std::ostream& fout,
const char* source, const char* source,
const cmCustomCommand& command, const cmCustomCommand& command,
const char* extraFlags); FCInfo& fcinfo);
void WriteTargetVersionAttribute(std::ostream& fout, cmTarget& target); void WriteTargetVersionAttribute(std::ostream& fout, cmTarget& target);
void WriteGroup(const cmSourceGroup *sg, void WriteGroup(const cmSourceGroup *sg,
@ -117,6 +119,8 @@ private:
const char *libName, std::vector<std::string> *configs); const char *libName, std::vector<std::string> *configs);
virtual std::string GetTargetDirectory(cmTarget const&) const; virtual std::string GetTargetDirectory(cmTarget const&) const;
friend class cmLocalVisualStudio7GeneratorFCInfo;
cmVS7FlagTable const* ExtraFlagTable; cmVS7FlagTable const* ExtraFlagTable;
std::string ModuleDefinitionFile; std::string ModuleDefinitionFile;
int Version; int Version;

View File

@ -254,6 +254,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
{ {
const char *lang = l->c_str(); const char *lang = l->c_str();
std::string flags; std::string flags;
std::string defines;
bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) || bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) ||
(this->Target->GetType() == cmTarget::MODULE_LIBRARY)); (this->Target->GetType() == cmTarget::MODULE_LIBRARY));
@ -264,6 +265,15 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
flags += exportMacro; 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. // Add language-specific flags.
this->LocalGenerator this->LocalGenerator
->AddLanguageFlags(flags, lang, ->AddLanguageFlags(flags, lang,
@ -286,6 +296,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
AppendFlags(flags,this->GetFrameworkFlags().c_str()); AppendFlags(flags,this->GetFrameworkFlags().c_str());
*this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n"; *this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n";
*this->FlagFileStream << lang << "_DEFINES = " << defines << "\n\n";
} }
// Add target-specific flags. // Add target-specific flags.
@ -437,6 +448,35 @@ cmMakefileTargetGenerator
<< "\n"; << "\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. // Get the output paths for source and object files.
std::string sourceFile = source.GetFullPath(); std::string sourceFile = source.GetFullPath();
if(this->LocalGenerator->UseRelativePaths) if(this->LocalGenerator->UseRelativePaths)
@ -522,6 +562,7 @@ cmMakefileTargetGenerator
std::string objectDir = cmSystemTools::GetFilenamePath(obj); std::string objectDir = cmSystemTools::GetFilenamePath(obj);
vars.ObjectDir = objectDir.c_str(); vars.ObjectDir = objectDir.c_str();
vars.Flags = flags.c_str(); vars.Flags = flags.c_str();
vars.Defines = defines.c_str();
// Expand placeholders in the commands. // Expand placeholders in the commands.
for(std::vector<std::string>::iterator i = commands.begin(); for(std::vector<std::string>::iterator i = commands.begin();
@ -601,7 +642,11 @@ cmMakefileTargetGenerator
preprocessCommands.begin(), preprocessCommands.begin(),
preprocessCommands.end()); 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. // Expand placeholders in the commands.
for(std::vector<std::string>::iterator i = commands.begin(); for(std::vector<std::string>::iterator i = commands.begin();
@ -653,7 +698,11 @@ cmMakefileTargetGenerator
assemblyCommands.begin(), assemblyCommands.begin(),
assemblyCommands.end()); 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. // Expand placeholders in the commands.
for(std::vector<std::string>::iterator i = commands.begin(); for(std::vector<std::string>::iterator i = commands.begin();

View File

@ -340,7 +340,33 @@ void cmSourceFile::DefineProperties(cmake *cm)
("COMPILE_FLAGS", cmProperty::SOURCE_FILE, ("COMPILE_FLAGS", cmProperty::SOURCE_FILE,
"Additional flags to be added when compiling this source file.", "Additional flags to be added when compiling this source file.",
"These flags will be added to the list of compile flags when " "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 cm->DefineProperty
("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE, ("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE,

View File

@ -67,8 +67,32 @@ void cmTarget::DefineProperties(cmake *cm)
("COMPILE_FLAGS", cmProperty::TARGET, ("COMPILE_FLAGS", cmProperty::TARGET,
"Additional flags to use when compiling this target's sources.", "Additional flags to use when compiling this target's sources.",
"The COMPILE_FLAGS property sets additional compiler flags used " "The COMPILE_FLAGS property sets additional compiler flags used "
"to build sources within the target. It may also be used to pass " "to build sources within the target. Use COMPILE_DEFINITIONS "
"additional preprocessor 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 cm->DefineProperty
("DEFINE_SYMBOL", cmProperty::TARGET, ("DEFINE_SYMBOL", cmProperty::TARGET,

View File

@ -49,6 +49,7 @@ IF(BUILD_TESTING)
ADD_TEST_MACRO(Properties Properties) ADD_TEST_MACRO(Properties Properties)
ADD_TEST_MACRO(Assembler HelloAsm) ADD_TEST_MACRO(Assembler HelloAsm)
ADD_TEST_MACRO(SourceGroups SourceGroups) ADD_TEST_MACRO(SourceGroups SourceGroups)
ADD_TEST_MACRO(Preprocess Preprocess)
IF (CMAKE_STRICT) IF (CMAKE_STRICT)
ADD_TEST_MACRO(DocTest DocTest) ADD_TEST_MACRO(DocTest DocTest)

View File

@ -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})

View File

@ -0,0 +1 @@
#define FILE_PATH_DEF

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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; }

View File

@ -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"

View File

@ -0,0 +1 @@
#define TARGET_PATH_DEF