Commit 8262ccfd authored by Brad King's avatar Brad King

ENH: Create COMPILE_DEFINITIONS property for targets and source files. Create...

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.
parent 2c42f755
......@@ -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)
......
......@@ -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)
......
......@@ -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)
......
......@@ -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>")
......
......@@ -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)
......@@ -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
......
......@@ -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
......
......@@ -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}")
......
......@@ -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}")
......
......@@ -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 += "'";
}
}
......@@ -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"; }
......
......@@ -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")
......@@ -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
cmLocalGenerator::ConstructComment(const cmCustomCommand& cc,
......@@ -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;
}
......@@ -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
......
......@@ -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;
}
......
......@@ -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;
}
......@@ -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
......
This diff is collapsed.
......@@ -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;
......
......@@ -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(),