DEVTOOLS: Add precompiled header support to MSBuild/MSVC.

This commit is contained in:
elasota
2022-12-24 09:54:18 -05:00
committed by Daniel
parent f22326d4a7
commit 667cb63823
11 changed files with 396 additions and 57 deletions
+1
View File
@@ -8,6 +8,7 @@
*.dwp
lib*.a
.deps
*_pch.cpp
/config.log
/scummvm
+6 -5
View File
@@ -270,7 +270,7 @@ static std::string filePrefix(const BuildSetup &setup, const std::string &module
}
void CMakeProvider::createProjectFile(const std::string &name, const std::string &, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) {
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
const std::string projectFile = setup.outputDir + "/CMakeLists.txt";
std::ofstream project(projectFile.c_str(), std::ofstream::out | std::ofstream::app);
@@ -284,12 +284,12 @@ void CMakeProvider::createProjectFile(const std::string &name, const std::string
project << "add_library(" << name << "\n";
} else {
enginesStr << "add_engine(" << name << "\n";
addFilesToProject(moduleDir, enginesStr, includeList, excludeList, filePrefix(setup, moduleDir));
addFilesToProject(moduleDir, enginesStr, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, filePrefix(setup, moduleDir));
enginesStr << ")\n\n";
return;
}
addFilesToProject(moduleDir, project, includeList, excludeList, filePrefix(setup, moduleDir));
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, filePrefix(setup, moduleDir));
project << ")\n";
project << "\n";
@@ -356,12 +356,13 @@ void CMakeProvider::writeDefines(const BuildSetup &setup, std::ofstream &output)
}
void CMakeProvider::writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix) {
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
std::string lastName;
for (const FileNode *node : dir.children) {
if (!node->children.empty()) {
writeFileListToProject(*node, projectFile, indentation + 1, objPrefix + node->name + '_', filePrefix + node->name + '/');
writeFileListToProject(*node, projectFile, indentation + 1, objPrefix + node->name + '_', filePrefix + node->name + '/', pchIncludeRoot, pchDirs, pchExclude);
} else {
std::string name, ext;
splitFilename(node->name, name, ext);
+3 -2
View File
@@ -45,10 +45,11 @@ protected:
void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) final {}
void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) final;
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix) final;
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
const char *getProjectExtension() final;
+6 -5
View File
@@ -97,7 +97,7 @@ StringList getFeatureLibraries(const BuildSetup &setup) {
}
void CodeBlocksProvider::createProjectFile(const std::string &name, const std::string &, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) {
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
const std::string projectFile = setup.outputDir + '/' + name + getProjectExtension();
std::ofstream project(projectFile.c_str());
@@ -210,9 +210,9 @@ void CodeBlocksProvider::createProjectFile(const std::string &name, const std::s
}
if (!modulePath.empty())
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix + '/' + modulePath);
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix + '/' + modulePath);
else
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix);
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix);
project << "\t\t<Extensions>\n"
@@ -249,13 +249,14 @@ void CodeBlocksProvider::writeDefines(const StringList &defines, std::ofstream &
}
void CodeBlocksProvider::writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix) {
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) {
const FileNode *node = *i;
if (!node->children.empty()) {
writeFileListToProject(*node, projectFile, indentation + 1, objPrefix + node->name + '_', filePrefix + node->name + '/');
writeFileListToProject(*node, projectFile, indentation + 1, objPrefix + node->name + '_', filePrefix + node->name + '/', pchIncludeRoot, pchDirs, pchExclude);
} else {
std::string name, ext;
splitFilename(node->name, name, ext);
+3 -2
View File
@@ -39,10 +39,11 @@ protected:
void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) final;
void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) final;
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix) final;
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
void writeReferences(const BuildSetup &setup, std::ofstream &output) final;
+141 -24
View File
@@ -1319,6 +1319,55 @@ void splitPath(const std::string &path, std::string &dir, std::string &file) {
file = (sep == std::string::npos) ? std::string() : path.substr(sep + 1);
}
bool calculatePchPaths(const std::string &sourceFilePath, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude, char separator, std::string &outPchIncludePath, std::string &outPchFilePath, std::string &outPchFileName) {
std::string compareName, extensionName;
splitFilename(sourceFilePath, compareName, extensionName);
// Is this file excluded?
if (std::find(pchExclude.begin(), pchExclude.end(), compareName) != pchExclude.end())
return false;
size_t lastDelimiter = sourceFilePath.find_last_of(separator);
if (lastDelimiter == std::string::npos)
lastDelimiter = 0;
std::string pchDirectory = sourceFilePath.substr(0, lastDelimiter);
if (std::find(pchDirs.begin(), pchDirs.end(), pchDirectory) == pchDirs.end())
return false;
// This file uses a PCH
if (pchDirectory.size() < pchIncludeRoot.size() || pchDirectory.substr(0, pchIncludeRoot.size()) != pchIncludeRoot) {
error("PCH prefix for file '" + sourceFilePath + "' wasn't located under PCH include root '" + pchIncludeRoot + "'");
}
size_t pchDirNamePos = pchDirectory.find_last_of(separator);
if (pchDirNamePos == std::string::npos)
pchDirNamePos = 0;
else
pchDirNamePos++;
std::string pchFileName = pchDirectory.substr(pchDirNamePos) + "_pch.h";
std::string pchPath = (pchDirectory + separator + pchFileName);
// Convert to the local file prefix
std::string includePath = pchPath.substr(pchIncludeRoot.size());
if (separator != '/') {
for (std::string::iterator ch = includePath.begin(), chEnd = includePath.end(); ch != chEnd; ++ch) {
if (*ch == separator)
*ch = '/';
}
}
outPchIncludePath = includePath;
outPchFilePath = pchPath;
outPchFileName = pchFileName;
return true;
}
std::string basename(const std::string &fileName) {
const std::string::size_type slash = fileName.find_last_of('/');
if (slash == std::string::npos)
@@ -1586,7 +1635,7 @@ void ProjectProvider::createProject(BuildSetup &setup) {
createWorkspace(setup);
StringList in, ex;
StringList in, ex, pchDirs, pchEx;
// Create project files
for (UUIDMap::const_iterator i = _engineUuidMap.begin(); i != _engineUuidMap.end(); ++i) {
@@ -1595,11 +1644,13 @@ void ProjectProvider::createProject(BuildSetup &setup) {
// Retain the files between engines if we're creating a single project
in.clear();
ex.clear();
pchDirs.clear();
pchEx.clear();
const std::string moduleDir = setup.srcDir + targetFolder + i->first;
createModuleList(moduleDir, setup.defines, setup.testDirs, in, ex);
createProjectFile(i->first, i->second, setup, moduleDir, in, ex);
createModuleList(moduleDir, setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createProjectFile(i->first, i->second, setup, moduleDir, in, ex, setup.srcDir + targetFolder, pchDirs, pchEx);
}
// Create engine-detection submodules.
@@ -1623,37 +1674,40 @@ void ProjectProvider::createProject(BuildSetup &setup) {
}
for (std::vector<std::string>::const_iterator i = detectionModuleDirs.begin(), end = detectionModuleDirs.end(); i != end; ++i) {
createModuleList(*i, setup.defines, setup.testDirs, in, ex, true);
StringList tempPchDirs, tempSchEx; // No PCH for detection
createModuleList(*i, setup.defines, setup.testDirs, in, ex, tempPchDirs, tempSchEx, true);
}
createProjectFile(detProject, detUUID, setup, setup.srcDir + "/engines", in, ex);
createProjectFile(detProject, detUUID, setup, setup.srcDir + "/engines", in, ex, "", StringList(), StringList());
}
if (!setup.devTools) {
// Last but not least create the main project file.
in.clear();
ex.clear();
pchDirs.clear();
pchEx.clear();
// File list for the Project file
createModuleList(setup.srcDir + "/backends", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/base", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/common", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/common/compression", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/common/formats", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/common/lua", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/engines", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/graphics", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/gui", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/audio", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/video", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/image", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/math", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/backends", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/base", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/common", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/common/compression", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/common/formats", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/common/lua", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/engines", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/graphics", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/gui", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/audio", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/video", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/image", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
createModuleList(setup.srcDir + "/math", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
if (getFeatureBuildState("mt32emu", setup.features))
createModuleList(setup.srcDir + "/audio/softsynth/mt32", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/audio/softsynth/mt32", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
if (setup.tests) {
createModuleList(setup.srcDir + "/test", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/test", setup.defines, setup.testDirs, in, ex, pchDirs, pchEx);
} else {
// Resource files
addResourceFiles(setup, in, ex);
@@ -1678,7 +1732,7 @@ void ProjectProvider::createProject(BuildSetup &setup) {
}
// Create the main project file.
createProjectFile(setup.projectName, svmUUID, setup, setup.srcDir, in, ex);
createProjectFile(setup.projectName, svmUUID, setup, setup.srcDir, in, ex, setup.srcDir + '/', pchDirs, pchEx);
}
// Create other misc. build files
@@ -1827,15 +1881,16 @@ std::string ProjectProvider::getLastPathComponent(const std::string &path) {
void ProjectProvider::addFilesToProject(const std::string &dir, std::ostream &projectFile,
const StringList &includeList, const StringList &excludeList,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude,
const std::string &filePrefix) {
FileNode *files = scanFiles(dir, includeList, excludeList);
writeFileListToProject(*files, projectFile, 0, std::string(), filePrefix + '/');
writeFileListToProject(*files, projectFile, 0, std::string(), filePrefix + '/', pchIncludeRoot, pchDirs, pchExclude);
delete files;
}
void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList, bool forDetection) const {
void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList, StringList &pchDirs, StringList &pchExclude, bool forDetection) const {
const std::string moduleMkFile = moduleDir + "/module.mk";
std::ifstream moduleMk(moduleMkFile.c_str());
if (!moduleMk)
@@ -1948,6 +2003,68 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin
++i;
}
}
} else if (*i == "MODULE_PCH_DIRS") {
if (tokens.size() < 3)
error("Malformed MODULE_PCH_DIRS definition in " + moduleMkFile);
++i;
// This is not exactly correct, for example an ":=" would usually overwrite
// all already added files, but since we do only save the files inside
// includeList or excludeList currently, we couldn't handle such a case easily.
// (includeList and excludeList should always preserve their entries, not added
// by this function, thus we can't just clear them on ":=" or "=").
// But hopefully our module.mk files will never do such things anyway.
if (*i != ":=" && *i != "+=" && *i != "=")
error("Malformed MODULE_PCH_DIRS definition in " + moduleMkFile);
++i;
while (i != tokens.end()) {
if (*i == "\\") {
std::getline(moduleMk, line);
tokens = tokenize(line);
i = tokens.begin();
} else {
std::string filename = moduleDir;
if ((*i) != ".")
filename += "/" + unifyPath(*i);
if (shouldInclude.top())
pchDirs.push_back(filename);
++i;
}
}
} else if (*i == "MODULE_PCH_EXCLUDE") {
if (tokens.size() < 3)
error("Malformed MODULE_PCH_EXCLUDE definition in " + moduleMkFile);
++i;
// This is not exactly correct, for example an ":=" would usually overwrite
// all already added files, but since we do only save the files inside
// includeList or excludeList currently, we couldn't handle such a case easily.
// (includeList and excludeList should always preserve their entries, not added
// by this function, thus we can't just clear them on ":=" or "=").
// But hopefully our module.mk files will never do such things anyway.
if (*i != ":=" && *i != "+=" && *i != "=")
error("Malformed MODULE_PCH_EXCLUDE definition in " + moduleMkFile);
++i;
while (i != tokens.end()) {
if (*i == "\\") {
std::getline(moduleMk, line);
tokens = tokenize(line);
i = tokens.begin();
} else {
const std::string filename = moduleDir + "/" + unifyPath(*i);
if (shouldInclude.top())
pchExclude.push_back(filename);
++i;
}
}
} else if (*i == "KYRARPG_COMMON_OBJ") {
// HACK to fix EOB/LOL compilation in the kyra engine: add the
// files defined in the KYRARPG_COMMON_OBJ variable in a list
+21 -4
View File
@@ -409,6 +409,21 @@ void splitFilename(const std::string &fileName, std::string &name, std::string &
*/
void splitPath(const std::string &path, std::string &dir, std::string &file);
/**
* Calculates the include path and PCH file path (without the base directory).
*
* @param filePath Path to the source file.
* @param pchIncludeRoot Path to the PCH inclusion root directory (ending with separator).
* @param pchDirs List of PCH directories.
* @param pchExclude List of PCH exclusions.
* @param separator Path separator
* @param outPchIncludePath Output path to be used by #include directives.
* @param outPchFilePath Output file path.
* @param outPchFileName Output file name.
* @return True if the file path uses PCH, false if not.
*/
bool calculatePchPaths(const std::string &sourceFilePath, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude, char separator, std::string &outPchIncludePath, std::string &outPchFilePath, std::string &outPchFileName);
/**
* Returns the basename of a path.
* examples:
@@ -551,7 +566,7 @@ protected:
* @param excludeList Files to exclude (must have "moduleDir" as prefix).
*/
virtual void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) = 0;
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) = 0;
/**
* Writes file entries for the specified directory node into
@@ -564,7 +579,8 @@ protected:
* @param filePrefix Generic prefix to all files of the node.
*/
virtual void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix) = 0;
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) = 0;
/**
* Output a list of project references to the file stream
@@ -588,7 +604,8 @@ protected:
* @param filePrefix Prefix to use for relative path arguments.
*/
void addFilesToProject(const std::string &dir, std::ostream &projectFile,
const StringList &includeList, const StringList &excludeList,
const StringList &includeList, const StringList &excludeList,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude,
const std::string &filePrefix);
/**
@@ -602,7 +619,7 @@ protected:
* @param includeList Reference to a list, where included files should be added.
* @param excludeList Reference to a list, where excluded files should be added.
*/
void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList, bool forDetection = false) const;
void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList, StringList &pchDirs, StringList &pchExclude, bool forDetection = false) const;
/**
* Creates an UUID for every enabled engine of the
+190 -5
View File
@@ -81,7 +81,7 @@ inline void outputProperties(const BuildSetup &setup, std::ostream &project, con
} // End of anonymous namespace
void MSBuildProvider::createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) {
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
const std::string projectFile = setup.outputDir + '/' + name + getProjectExtension();
std::ofstream project(projectFile.c_str());
if (!project || !project.is_open()) {
@@ -156,9 +156,9 @@ void MSBuildProvider::createProjectFile(const std::string &name, const std::stri
}
if (!modulePath.empty())
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix + '/' + modulePath);
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix + '/' + modulePath);
else
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix);
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix);
// Output references for the main project
if (name == setup.projectName)
@@ -529,8 +529,52 @@ void MSBuildProvider::outputNasmCommand(std::ostream &projectFile, const std::st
}
}
void MSBuildProvider::insertPathIntoDirectory(FileNode &dir, const std::string &path) {
size_t separatorLoc = path.find('\\');
if (separatorLoc != std::string::npos) {
// Inside of a subdirectory
std::string subdirName = path.substr(0, separatorLoc);
FileNode::NodeList::iterator dirIt = dir.children.begin();
FileNode::NodeList::iterator dirItEnd = dir.children.end();
while (dirIt != dirItEnd) {
if ((*dirIt)->name == subdirName)
break;
++dirIt;
}
FileNode *dirNode = nullptr;
if (dirIt == dirItEnd) {
dirNode = new FileNode(subdirName);
dir.children.push_back(dirNode);
} else {
dirNode = *dirIt;
}
insertPathIntoDirectory(*dirNode, path.substr(separatorLoc + 1));
} else {
FileNode *fileNode = new FileNode(path);
dir.children.push_back(fileNode);
}
}
void MSBuildProvider::createFileNodesFromPCHList(FileNode &dir, const std::string &pathBase, const StringList &pchCompileFiles) {
for (StringList::const_iterator it = pchCompileFiles.begin(), itEnd = pchCompileFiles.end(); it != itEnd; ++it) {
const std::string &pchPath = *it;
if (pchPath.size() > pathBase.size() && pchPath.substr(0, pathBase.size()) == pathBase) {
std::string internalPath = pchPath.substr(pathBase.size());
insertPathIntoDirectory(dir, internalPath);
}
}
}
void MSBuildProvider::writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int,
const std::string &objPrefix, const std::string &filePrefix) {
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
// Reset lists
_filters.clear();
_compileFiles.clear();
@@ -544,12 +588,33 @@ void MSBuildProvider::writeFileListToProject(const FileNode &dir, std::ostream &
computeFileList(dir, objPrefix, filePrefix);
_filters.pop_back(); // remove last empty filter
StringList pchCompileFiles;
// Output compile, include, other and resource files
outputFiles(projectFile, _compileFiles, "ClCompile");
outputCompileFiles(projectFile, pchIncludeRoot, pchDirs, pchExclude, pchCompileFiles);
outputFiles(projectFile, _includeFiles, "ClInclude");
outputFiles(projectFile, _otherFiles, "None");
outputFiles(projectFile, _resourceFiles, "ResourceCompile");
if (pchCompileFiles.size() > 0) {
// Generate filters and additional compile files for PCH files
FileNode pchDir(dir.name);
createFileNodesFromPCHList(pchDir, convertPathToWin(dir.name) + '\\', pchCompileFiles);
StringList backupFilters = _filters;
_filters.clear();
_filters.push_back(""); // init filters
computeFileList(pchDir, objPrefix, filePrefix);
_filters.pop_back(); // remove last empty filter
// Combine lists, removing duplicates
for (StringList::const_iterator it = backupFilters.begin(), itEnd = backupFilters.end(); it != itEnd; ++it) {
if (std::find(_filters.begin(), _filters.end(), *it) != _filters.end())
_filters.push_back(*it);
}
}
// Output asm files
if (!_asmFiles.empty()) {
projectFile << "\t<ItemGroup>\n";
@@ -579,6 +644,126 @@ void MSBuildProvider::outputFiles(std::ostream &projectFile, const FileEntries &
}
}
void MSBuildProvider::outputCompileFiles(std::ostream &projectFile, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude, StringList &outPCHFiles) {
const FileEntries &files = _compileFiles;
const bool hasPCH = (pchDirs.size() > 0);
std::string pchIncludeRootWin;
StringList pchDirsWin;
StringList pchExcludeWin;
if (hasPCH) {
pchIncludeRootWin = convertPathToWin(pchIncludeRoot);
// Convert PCH paths to Win
for (StringList::const_iterator entry = pchDirs.begin(), end = pchDirs.end(); entry != end; ++entry) {
std::string convertedPath = convertPathToWin(*entry);
if (convertedPath.size() < pchIncludeRootWin.size() || convertedPath.substr(0, pchIncludeRootWin.size()) != pchIncludeRootWin) {
error("PCH path '" + convertedPath + "' wasn't located under PCH include root '" + pchIncludeRootWin + "'");
}
pchDirsWin.push_back(convertPathToWin(*entry));
}
for (StringList::const_iterator entry = pchExclude.begin(), end = pchExclude.end(); entry != end; ++entry) {
const std::string path = *entry;
if (path.size() >= 2 && path[path.size() - 1] == 'o' && path[path.size() - 2] == '.')
pchExcludeWin.push_back(convertPathToWin(path.substr(0, path.size() - 2)));
}
}
std::map<std::string, PCHInfo> pchMap;
if (!files.empty()) {
projectFile << "\t<ItemGroup>\n";
for (FileEntries::const_iterator entry = files.begin(), end = files.end(); entry != end; ++entry) {
std::string pchIncludePath, pchFilePath, pchFileName;
bool fileHasPCH = false;
if (hasPCH)
fileHasPCH = calculatePchPaths(entry->path, pchIncludeRootWin, pchDirsWin, pchExcludeWin, '\\', pchIncludePath, pchFilePath, pchFileName);
if (fileHasPCH) {
std::string pchOutputFileName = "$(IntDir)dists\\msvc\\%(RelativeDir)" + pchFileName.substr(0, pchFileName.size() - 2) + ".pch";
PCHInfo &pchInfo = pchMap[pchFilePath];
pchInfo.file = pchIncludePath;
pchInfo.outputFile = pchOutputFileName;
projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\">\n";
projectFile << "\t\t\t<PrecompiledHeader>Use</PrecompiledHeader>\n";
projectFile << "\t\t\t<PrecompiledHeaderFile>" << pchIncludePath << "</PrecompiledHeaderFile>\n";
projectFile << "\t\t\t<PrecompiledHeaderOutputFile>" << pchOutputFileName << "</PrecompiledHeaderOutputFile>\n";
projectFile << "\t\t</ClCompile>\n";
} else {
projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\" />\n";
}
}
// Flush PCH files
for (std::map<std::string, PCHInfo>::const_iterator pchIt = pchMap.begin(), pchItEnd = pchMap.end(); pchIt != pchItEnd; ++pchIt) {
const PCHInfo &pchInfo = pchIt->second;
const std::string &filePath = pchIt->first;
assert(filePath.size() >= 2 && filePath.substr(filePath.size() - 2) == ".h");
std::string cppFilePath = filePath.substr(0, filePath.size() - 2) + ".cpp";
std::string expectedContents = "/* This file is automatically generated by create_project */\n"
"/* DO NOT EDIT MANUALLY */\n"
"#include \"" + pchInfo.file + "\"\n";
// Try to avoid touching the generated .cpp if it's identical to the expected output.
// If we touch the file, then every file that includes PCH needs to be recompiled.
std::ifstream pchInputFile(cppFilePath.c_str());
bool needToEmit = true;
if (pchInputFile && pchInputFile.is_open()) {
std::string fileContents;
for (;;) {
char buffer[1024];
size_t numRead = sizeof(buffer) - 1;
pchInputFile.read(buffer, numRead);
buffer[pchInputFile.gcount()] = '\0';
fileContents += buffer;
if (pchInputFile.eof() || pchInputFile.fail())
break;
if (fileContents.size() > expectedContents.size())
break;
}
needToEmit = (fileContents != expectedContents);
pchInputFile.close();
}
if (needToEmit) {
std::ofstream pchOutputFile(cppFilePath.c_str());
if (!pchOutputFile || !pchOutputFile.is_open()) {
error("Could not open \"" + cppFilePath + "\" for writing");
return;
}
pchOutputFile << expectedContents;
pchOutputFile.close();
}
projectFile << "\t\t<ClCompile Include=\"" << cppFilePath << "\">\n";
projectFile << "\t\t\t<PrecompiledHeader>Create</PrecompiledHeader>\n";
projectFile << "\t\t\t<PrecompiledHeaderFile>" << pchInfo.file << "</PrecompiledHeaderFile>\n";
projectFile << "\t\t\t<PrecompiledHeaderOutputFile>" << pchInfo.outputFile << "</PrecompiledHeaderOutputFile>\n";
projectFile << "\t\t</ClCompile>\n";
outPCHFiles.push_back(cppFilePath);
}
projectFile << "\t</ItemGroup>\n";
}
}
void MSBuildProvider::computeFileList(const FileNode &dir, const std::string &objPrefix, const std::string &filePrefix) {
for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) {
const FileNode *node = *i;
+12 -2
View File
@@ -32,12 +32,13 @@ public:
protected:
void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) override;
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) override;
void outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, MSVC_Architecture arch, const std::string &configuration);
void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix) override;
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) override;
void writeReferences(const BuildSetup &setup, std::ofstream &output) override;
@@ -61,6 +62,11 @@ private:
};
typedef std::list<FileEntry> FileEntries;
struct PCHInfo {
std::string file;
std::string outputFile;
};
std::list<std::string> _filters; // list of filters (we need to create a GUID for each filter id)
FileEntries _compileFiles;
FileEntries _includeFiles;
@@ -73,8 +79,12 @@ private:
void outputFilter(std::ostream &filters, const FileEntries &files, const std::string &action);
void outputFiles(std::ostream &projectFile, const FileEntries &files, const std::string &action);
void outputCompileFiles(std::ostream &projectFile, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude, StringList &outPCHFiles);
void outputNasmCommand(std::ostream &projectFile, const std::string &config, const std::string &prefix);
static void createFileNodesFromPCHList(FileNode &dir, const std::string &pathBase, const StringList &pchCompileFiles);
static void insertPathIntoDirectory(FileNode &dir, const std::string &path);
};
} // namespace CreateProjectTool
+9 -6
View File
@@ -307,8 +307,10 @@ void XcodeProvider::addResourceFiles(const BuildSetup &setup, StringList &includ
includeList.push_back(setup.srcDir + "/" + *it);
}
StringList pchDirs, pchEx;
StringList td;
createModuleList(setup.srcDir + "/backends/platform/ios7", setup.defines, td, includeList, excludeList);
createModuleList(setup.srcDir + "/backends/platform/ios7", setup.defines, td, includeList, excludeList, pchDirs, pchEx);
}
void XcodeProvider::createWorkspace(const BuildSetup &setup) {
@@ -343,7 +345,7 @@ void XcodeProvider::createOtherBuildFiles(const BuildSetup &setup) {
// Store information about a project here, for use at the end
void XcodeProvider::createProjectFile(const std::string &, const std::string &, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) {
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
std::string modulePath;
if (!moduleDir.compare(0, setup.srcDir.size(), setup.srcDir)) {
modulePath = moduleDir.substr(setup.srcDir.size());
@@ -353,9 +355,9 @@ void XcodeProvider::createProjectFile(const std::string &, const std::string &,
std::ofstream project;
if (!modulePath.empty())
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix + '/' + modulePath);
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix + '/' + modulePath);
else
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix);
addFilesToProject(moduleDir, project, includeList, excludeList, pchIncludeRoot, pchDirs, pchExclude, setup.filePrefix);
}
//////////////////////////////////////////////////////////////////////////
@@ -402,7 +404,8 @@ void XcodeProvider::outputMainProjectFile(const BuildSetup &setup) {
// Files
//////////////////////////////////////////////////////////////////////////
void XcodeProvider::writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix) {
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) {
// Ensure that top-level groups are generated for i.e. engines/
Group *group = touchGroupsForPath(filePrefix);
@@ -416,7 +419,7 @@ void XcodeProvider::writeFileListToProject(const FileNode &dir, std::ostream &pr
}
// Process child nodes
if (!node->children.empty())
writeFileListToProject(*node, projectFile, indentation + 1, objPrefix + node->name + '_', filePrefix + node->name + '/');
writeFileListToProject(*node, projectFile, indentation + 1, objPrefix + node->name + '_', filePrefix + node->name + '/', pchIncludeRoot, pchDirs, pchExclude);
}
}
+4 -2
View File
@@ -42,10 +42,12 @@ protected:
void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) final;
void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) final;
const StringList &includeList, const StringList &excludeList, const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
void writeFileListToProject(const FileNode &dir, std::ostream &projectFile, const int indentation,
const std::string &objPrefix, const std::string &filePrefix) final;
const std::string &objPrefix, const std::string &filePrefix,
const std::string &pchIncludeRoot, const StringList &pchDirs, const StringList &pchExclude) final;
private:
enum {
kSettingsAsList = 0x01,