Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
370 lines
13 KiB
C++
370 lines
13 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
#include "cmExtraSublimeTextGenerator.h"
|
|
|
|
#include "cmGeneratedFileStream.h"
|
|
#include "cmGeneratorTarget.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmLocalGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmSourceFile.h"
|
|
#include "cmState.h"
|
|
#include "cmSystemTools.h"
|
|
|
|
#include <cmsys/RegularExpression.hxx>
|
|
#include <ostream>
|
|
#include <set>
|
|
#include <string.h>
|
|
#include <utility>
|
|
|
|
/*
|
|
Sublime Text 2 Generator
|
|
Author: Morné Chamberlain
|
|
This generator was initially based off of the CodeBlocks generator.
|
|
|
|
Some useful URLs:
|
|
Homepage:
|
|
http://www.sublimetext.com/
|
|
|
|
File format docs:
|
|
http://www.sublimetext.com/docs/2/projects.html
|
|
http://sublimetext.info/docs/en/reference/build_systems.html
|
|
*/
|
|
|
|
cmExternalMakefileProjectGeneratorFactory*
|
|
cmExtraSublimeTextGenerator::GetFactory()
|
|
{
|
|
static cmExternalMakefileProjectGeneratorSimpleFactory<
|
|
cmExtraSublimeTextGenerator>
|
|
factory("Sublime Text 2", "Generates Sublime Text 2 project files.");
|
|
|
|
if (factory.GetSupportedGlobalGenerators().empty()) {
|
|
#if defined(_WIN32)
|
|
factory.AddSupportedGlobalGenerator("MinGW Makefiles");
|
|
factory.AddSupportedGlobalGenerator("NMake Makefiles");
|
|
// disable until somebody actually tests it:
|
|
// factory.AddSupportedGlobalGenerator("MSYS Makefiles");
|
|
#endif
|
|
factory.AddSupportedGlobalGenerator("Ninja");
|
|
factory.AddSupportedGlobalGenerator("Unix Makefiles");
|
|
}
|
|
|
|
return &factory;
|
|
}
|
|
|
|
cmExtraSublimeTextGenerator::cmExtraSublimeTextGenerator()
|
|
: cmExternalMakefileProjectGenerator()
|
|
{
|
|
}
|
|
|
|
void cmExtraSublimeTextGenerator::Generate()
|
|
{
|
|
// for each sub project in the project create a sublime text 2 project
|
|
for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
|
|
it = this->GlobalGenerator->GetProjectMap().begin();
|
|
it != this->GlobalGenerator->GetProjectMap().end(); ++it) {
|
|
// create a project file
|
|
this->CreateProjectFile(it->second);
|
|
}
|
|
}
|
|
|
|
void cmExtraSublimeTextGenerator::CreateProjectFile(
|
|
const std::vector<cmLocalGenerator*>& lgs)
|
|
{
|
|
std::string outputDir = lgs[0]->GetCurrentBinaryDirectory();
|
|
std::string projectName = lgs[0]->GetProjectName();
|
|
|
|
const std::string filename =
|
|
outputDir + "/" + projectName + ".sublime-project";
|
|
|
|
this->CreateNewProjectFile(lgs, filename);
|
|
}
|
|
|
|
void cmExtraSublimeTextGenerator::CreateNewProjectFile(
|
|
const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
|
|
{
|
|
const cmMakefile* mf = lgs[0]->GetMakefile();
|
|
cmGeneratedFileStream fout(filename.c_str());
|
|
if (!fout) {
|
|
return;
|
|
}
|
|
|
|
const std::string& sourceRootRelativeToOutput = cmSystemTools::RelativePath(
|
|
lgs[0]->GetBinaryDirectory(), lgs[0]->GetSourceDirectory());
|
|
// Write the folder entries to the project file
|
|
fout << "{\n";
|
|
fout << "\t\"folders\":\n\t[\n\t";
|
|
if (!sourceRootRelativeToOutput.empty()) {
|
|
fout << "\t{\n\t\t\t\"path\": \"" << sourceRootRelativeToOutput << "\"";
|
|
const std::string& outputRelativeToSourceRoot =
|
|
cmSystemTools::RelativePath(lgs[0]->GetSourceDirectory(),
|
|
lgs[0]->GetBinaryDirectory());
|
|
if ((!outputRelativeToSourceRoot.empty()) &&
|
|
((outputRelativeToSourceRoot.length() < 3) ||
|
|
(outputRelativeToSourceRoot.substr(0, 3) != "../"))) {
|
|
fout << ",\n\t\t\t\"folder_exclude_patterns\": [\""
|
|
<< outputRelativeToSourceRoot << "\"]";
|
|
}
|
|
} else {
|
|
fout << "\t{\n\t\t\t\"path\": \"./\"";
|
|
}
|
|
fout << "\n\t\t}";
|
|
// End of the folders section
|
|
fout << "\n\t]";
|
|
|
|
// Write the beginning of the build systems section to the project file
|
|
fout << ",\n\t\"build_systems\":\n\t[\n\t";
|
|
|
|
// Set of include directories over all targets (sublime text/sublimeclang
|
|
// doesn't currently support these settings per build system, only project
|
|
// wide
|
|
MapSourceFileFlags sourceFileFlags;
|
|
AppendAllTargets(lgs, mf, fout, sourceFileFlags);
|
|
|
|
// End of build_systems
|
|
fout << "\n\t]";
|
|
fout << "\n\t}";
|
|
}
|
|
|
|
void cmExtraSublimeTextGenerator::AppendAllTargets(
|
|
const std::vector<cmLocalGenerator*>& lgs, const cmMakefile* mf,
|
|
cmGeneratedFileStream& fout, MapSourceFileFlags& sourceFileFlags)
|
|
{
|
|
std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
|
|
std::string compiler = "";
|
|
if (!lgs.empty()) {
|
|
this->AppendTarget(fout, "all", lgs[0], CM_NULLPTR, make.c_str(), mf,
|
|
compiler.c_str(), sourceFileFlags, true);
|
|
this->AppendTarget(fout, "clean", lgs[0], CM_NULLPTR, make.c_str(), mf,
|
|
compiler.c_str(), sourceFileFlags, false);
|
|
}
|
|
|
|
// add all executable and library targets and some of the GLOBAL
|
|
// and UTILITY targets
|
|
for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
|
|
lg != lgs.end(); lg++) {
|
|
cmMakefile* makefile = (*lg)->GetMakefile();
|
|
std::vector<cmGeneratorTarget*> targets = (*lg)->GetGeneratorTargets();
|
|
for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
|
|
ti != targets.end(); ti++) {
|
|
std::string targetName = (*ti)->GetName();
|
|
switch ((*ti)->GetType()) {
|
|
case cmState::GLOBAL_TARGET: {
|
|
// Only add the global targets from CMAKE_BINARY_DIR,
|
|
// not from the subdirs
|
|
if (strcmp((*lg)->GetCurrentBinaryDirectory(),
|
|
(*lg)->GetBinaryDirectory()) == 0) {
|
|
this->AppendTarget(fout, targetName, *lg, CM_NULLPTR, make.c_str(),
|
|
makefile, compiler.c_str(), sourceFileFlags,
|
|
false);
|
|
}
|
|
} break;
|
|
case cmState::UTILITY:
|
|
// Add all utility targets, except the Nightly/Continuous/
|
|
// Experimental-"sub"targets as e.g. NightlyStart
|
|
if (((targetName.find("Nightly") == 0) &&
|
|
(targetName != "Nightly")) ||
|
|
((targetName.find("Continuous") == 0) &&
|
|
(targetName != "Continuous")) ||
|
|
((targetName.find("Experimental") == 0) &&
|
|
(targetName != "Experimental"))) {
|
|
break;
|
|
}
|
|
|
|
this->AppendTarget(fout, targetName, *lg, CM_NULLPTR, make.c_str(),
|
|
makefile, compiler.c_str(), sourceFileFlags,
|
|
false);
|
|
break;
|
|
case cmState::EXECUTABLE:
|
|
case cmState::STATIC_LIBRARY:
|
|
case cmState::SHARED_LIBRARY:
|
|
case cmState::MODULE_LIBRARY:
|
|
case cmState::OBJECT_LIBRARY: {
|
|
this->AppendTarget(fout, targetName, *lg, *ti, make.c_str(),
|
|
makefile, compiler.c_str(), sourceFileFlags,
|
|
false);
|
|
std::string fastTarget = targetName;
|
|
fastTarget += "/fast";
|
|
this->AppendTarget(fout, fastTarget, *lg, *ti, make.c_str(),
|
|
makefile, compiler.c_str(), sourceFileFlags,
|
|
false);
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void cmExtraSublimeTextGenerator::AppendTarget(
|
|
cmGeneratedFileStream& fout, const std::string& targetName,
|
|
cmLocalGenerator* lg, cmGeneratorTarget* target, const char* make,
|
|
const cmMakefile* makefile, const char* /*compiler*/,
|
|
MapSourceFileFlags& sourceFileFlags, bool firstTarget)
|
|
{
|
|
|
|
if (target != CM_NULLPTR) {
|
|
std::vector<cmSourceFile*> sourceFiles;
|
|
target->GetSourceFiles(sourceFiles,
|
|
makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
|
|
std::vector<cmSourceFile*>::const_iterator sourceFilesEnd =
|
|
sourceFiles.end();
|
|
for (std::vector<cmSourceFile*>::const_iterator iter = sourceFiles.begin();
|
|
iter != sourceFilesEnd; ++iter) {
|
|
cmSourceFile* sourceFile = *iter;
|
|
MapSourceFileFlags::iterator sourceFileFlagsIter =
|
|
sourceFileFlags.find(sourceFile->GetFullPath());
|
|
if (sourceFileFlagsIter == sourceFileFlags.end()) {
|
|
sourceFileFlagsIter =
|
|
sourceFileFlags
|
|
.insert(MapSourceFileFlags::value_type(sourceFile->GetFullPath(),
|
|
std::vector<std::string>()))
|
|
.first;
|
|
}
|
|
std::vector<std::string>& flags = sourceFileFlagsIter->second;
|
|
std::string flagsString = this->ComputeFlagsForObject(*iter, lg, target);
|
|
std::string definesString = this->ComputeDefines(*iter, lg, target);
|
|
flags.clear();
|
|
cmsys::RegularExpression flagRegex;
|
|
// Regular expression to extract compiler flags from a string
|
|
// https://gist.github.com/3944250
|
|
const char* regexString =
|
|
"(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?";
|
|
flagRegex.compile(regexString);
|
|
std::string workString = flagsString + " " + definesString;
|
|
while (flagRegex.find(workString)) {
|
|
std::string::size_type start = flagRegex.start();
|
|
if (workString[start] == ' ') {
|
|
start++;
|
|
}
|
|
flags.push_back(workString.substr(start, flagRegex.end() - start));
|
|
if (flagRegex.end() < workString.size()) {
|
|
workString = workString.substr(flagRegex.end());
|
|
} else {
|
|
workString = "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ninja uses ninja.build files (look for a way to get the output file name
|
|
// from cmMakefile or something)
|
|
std::string makefileName;
|
|
if (this->GlobalGenerator->GetName() == "Ninja") {
|
|
makefileName = "build.ninja";
|
|
} else {
|
|
makefileName = "Makefile";
|
|
}
|
|
if (!firstTarget) {
|
|
fout << ",\n\t";
|
|
}
|
|
fout << "\t{\n\t\t\t\"name\": \"" << lg->GetProjectName() << " - "
|
|
<< targetName << "\",\n";
|
|
fout << "\t\t\t\"cmd\": ["
|
|
<< this->BuildMakeCommand(make, makefileName.c_str(), targetName)
|
|
<< "],\n";
|
|
fout << "\t\t\t\"working_dir\": \"${project_path}\",\n";
|
|
fout << "\t\t\t\"file_regex\": \"^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$\"\n";
|
|
fout << "\t\t}";
|
|
}
|
|
|
|
// Create the command line for building the given target using the selected
|
|
// make
|
|
std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
|
|
const std::string& make, const char* makefile, const std::string& target)
|
|
{
|
|
std::string command = "\"";
|
|
command += make + "\"";
|
|
std::string generator = this->GlobalGenerator->GetName();
|
|
if (generator == "NMake Makefiles") {
|
|
std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
|
|
command += ", \"/NOLOGO\", \"/f\", \"";
|
|
command += makefileName + "\"";
|
|
command += ", \"VERBOSE=1\", \"";
|
|
command += target;
|
|
command += "\"";
|
|
} else if (generator == "Ninja") {
|
|
std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
|
|
command += ", \"-f\", \"";
|
|
command += makefileName + "\"";
|
|
command += ", \"-v\", \"";
|
|
command += target;
|
|
command += "\"";
|
|
} else {
|
|
std::string makefileName;
|
|
if (generator == "MinGW Makefiles") {
|
|
// no escaping of spaces in this case, see
|
|
// https://gitlab.kitware.com/cmake/cmake/issues/10014
|
|
makefileName = makefile;
|
|
} else {
|
|
makefileName = cmSystemTools::ConvertToOutputPath(makefile);
|
|
}
|
|
command += ", \"-f\", \"";
|
|
command += makefileName + "\"";
|
|
command += ", \"VERBOSE=1\", \"";
|
|
command += target;
|
|
command += "\"";
|
|
}
|
|
return command;
|
|
}
|
|
|
|
// TODO: Most of the code is picked up from the Ninja generator, refactor it.
|
|
std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
|
|
cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* gtgt)
|
|
{
|
|
std::string flags;
|
|
std::string language = source->GetLanguage();
|
|
if (language.empty()) {
|
|
language = "C";
|
|
}
|
|
std::string const& config =
|
|
lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
|
|
|
|
lg->GetTargetCompileFlags(gtgt, config, language, flags);
|
|
|
|
// Add include directory flags.
|
|
{
|
|
std::vector<std::string> includes;
|
|
lg->GetIncludeDirectories(includes, gtgt, language, config);
|
|
std::string includeFlags = lg->GetIncludeFlags(includes, gtgt, language,
|
|
true); // full include paths
|
|
lg->AppendFlags(flags, includeFlags);
|
|
}
|
|
|
|
// Add source file specific flags.
|
|
lg->AppendFlags(flags, source->GetProperty("COMPILE_FLAGS"));
|
|
|
|
return flags;
|
|
}
|
|
|
|
// TODO: Refactor with
|
|
// void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
|
|
std::string cmExtraSublimeTextGenerator::ComputeDefines(
|
|
cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* target)
|
|
|
|
{
|
|
std::set<std::string> defines;
|
|
cmMakefile* makefile = lg->GetMakefile();
|
|
const std::string& language = source->GetLanguage();
|
|
const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
|
|
|
|
// Add the export symbol definition for shared library objects.
|
|
if (const char* exportMacro = target->GetExportMacro()) {
|
|
lg->AppendDefines(defines, exportMacro);
|
|
}
|
|
|
|
// Add preprocessor definitions for this target and configuration.
|
|
lg->AddCompileDefinitions(defines, target, config, language);
|
|
lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS"));
|
|
{
|
|
std::string defPropName = "COMPILE_DEFINITIONS_";
|
|
defPropName += cmSystemTools::UpperCase(config);
|
|
lg->AppendDefines(defines, source->GetProperty(defPropName));
|
|
}
|
|
|
|
std::string definesString;
|
|
lg->JoinDefines(defines, definesString, language);
|
|
|
|
return definesString;
|
|
}
|