mirror of
https://github.com/Kitware/CMake.git
synced 2026-08-05 07:10:26 +00:00
cmake-server: Support codemodel filegroups for INTERFACE_SOURCES
This change returns information for INTERFACE_SOURCES. We add a flag to the filegroup to indicate if the target represents interface sources. Protocol version is updated to 1.3 since this is a change to what was released in cmake version 3.12.
This commit is contained in:
@@ -308,6 +308,9 @@ which will result in a response type "reply"::
|
|||||||
|
|
||||||
indicating that the server is ready for action.
|
indicating that the server is ready for action.
|
||||||
|
|
||||||
|
Protocol version 1.3 introduces an optional flag on the target filegroup
|
||||||
|
that indicates if the filegroup represents :prop_tgt:`INTERFACE_SOURCES`.
|
||||||
|
|
||||||
|
|
||||||
Type "globalSettings"
|
Type "globalSettings"
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
@@ -524,6 +527,8 @@ FileGroups are used to group sources using similar settings together.
|
|||||||
|
|
||||||
Each fileGroup object may contain the following keys:
|
Each fileGroup object may contain the following keys:
|
||||||
|
|
||||||
|
"isInterfaceSources"
|
||||||
|
true if the fileGroup represents :prop_tgt:`INTERFACE_SOURCES`.
|
||||||
"language"
|
"language"
|
||||||
contains the programming language used by all files in the group.
|
contains the programming language used by all files in the group.
|
||||||
"compileFlags"
|
"compileFlags"
|
||||||
@@ -538,6 +543,8 @@ Each fileGroup object may contain the following keys:
|
|||||||
"defines"
|
"defines"
|
||||||
with a list of defines in the form "SOMEVALUE" or "SOMEVALUE=42". This
|
with a list of defines in the form "SOMEVALUE" or "SOMEVALUE=42". This
|
||||||
value is encoded in the system's native shell format.
|
value is encoded in the system's native shell format.
|
||||||
|
"isGenerated"
|
||||||
|
true if the files were generated.
|
||||||
"sources"
|
"sources"
|
||||||
with a list of source files.
|
with a list of source files.
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ static const std::string kCTEST_COMMAND = "ctestCommand";
|
|||||||
static const std::string kCTEST_INFO = "ctestInfo";
|
static const std::string kCTEST_INFO = "ctestInfo";
|
||||||
static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion";
|
static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion";
|
||||||
static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided";
|
static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided";
|
||||||
|
static const std::string kIS_INTERFACE_SOURCES_KEY = "isInterfaceSources";
|
||||||
|
|
||||||
static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==[";
|
static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==[";
|
||||||
static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]";
|
static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]";
|
||||||
|
|||||||
@@ -256,7 +256,12 @@ bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/,
|
|||||||
|
|
||||||
std::pair<int, int> cmServerProtocol1::ProtocolVersion() const
|
std::pair<int, int> cmServerProtocol1::ProtocolVersion() const
|
||||||
{
|
{
|
||||||
return std::make_pair(1, 2);
|
// Revision history
|
||||||
|
// 1, 1 - Report backtraces in codemodel response
|
||||||
|
// 1, 2 - Add target install destinations to codemodel
|
||||||
|
// 1, 3 - Add a flag to target filegroups indicating whether or not the
|
||||||
|
// filegroup is for INTERFACE_SOURCES
|
||||||
|
return std::make_pair(1, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setErrorMessage(std::string* errorMessage, const std::string& text)
|
static void setErrorMessage(std::string* errorMessage, const std::string& text)
|
||||||
@@ -593,6 +598,8 @@ cmServerResponse cmServerProtocol1::ProcessCMakeInputs(
|
|||||||
return request.Reply(result);
|
return request.Reply(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string kInterfaceSourcesLanguageDataKey =
|
||||||
|
"INTERFACE_SOURCES_LD_KEY";
|
||||||
class LanguageData
|
class LanguageData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -625,6 +632,12 @@ void LanguageData::SetDefines(const std::set<std::string>& defines)
|
|||||||
Defines = std::move(result);
|
Defines = std::move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FileGroupSources
|
||||||
|
{
|
||||||
|
bool IsInterfaceSources;
|
||||||
|
std::vector<std::string> Files;
|
||||||
|
};
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@@ -652,31 +665,35 @@ struct hash<LanguageData>
|
|||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
static Json::Value DumpSourceFileGroup(const LanguageData& data,
|
static Json::Value DumpSourceFileGroup(const LanguageData& data,
|
||||||
|
bool isInterfaceSource,
|
||||||
const std::vector<std::string>& files,
|
const std::vector<std::string>& files,
|
||||||
const std::string& baseDir)
|
const std::string& baseDir)
|
||||||
{
|
{
|
||||||
Json::Value result = Json::objectValue;
|
Json::Value result = Json::objectValue;
|
||||||
|
|
||||||
|
if (isInterfaceSource) {
|
||||||
|
result[kIS_INTERFACE_SOURCES_KEY] = true;
|
||||||
|
}
|
||||||
if (!data.Language.empty()) {
|
if (!data.Language.empty()) {
|
||||||
result[kLANGUAGE_KEY] = data.Language;
|
result[kLANGUAGE_KEY] = data.Language;
|
||||||
if (!data.Flags.empty()) {
|
}
|
||||||
result[kCOMPILE_FLAGS_KEY] = data.Flags;
|
if (!data.Flags.empty()) {
|
||||||
}
|
result[kCOMPILE_FLAGS_KEY] = data.Flags;
|
||||||
if (!data.IncludePathList.empty()) {
|
}
|
||||||
Json::Value includes = Json::arrayValue;
|
if (!data.IncludePathList.empty()) {
|
||||||
for (auto const& i : data.IncludePathList) {
|
Json::Value includes = Json::arrayValue;
|
||||||
Json::Value tmp = Json::objectValue;
|
for (auto const& i : data.IncludePathList) {
|
||||||
tmp[kPATH_KEY] = i.first;
|
Json::Value tmp = Json::objectValue;
|
||||||
if (i.second) {
|
tmp[kPATH_KEY] = i.first;
|
||||||
tmp[kIS_SYSTEM_KEY] = i.second;
|
if (i.second) {
|
||||||
}
|
tmp[kIS_SYSTEM_KEY] = i.second;
|
||||||
includes.append(tmp);
|
|
||||||
}
|
}
|
||||||
result[kINCLUDE_PATH_KEY] = includes;
|
includes.append(tmp);
|
||||||
}
|
|
||||||
if (!data.Defines.empty()) {
|
|
||||||
result[kDEFINES_KEY] = fromStringList(data.Defines);
|
|
||||||
}
|
}
|
||||||
|
result[kINCLUDE_PATH_KEY] = includes;
|
||||||
|
}
|
||||||
|
if (!data.Defines.empty()) {
|
||||||
|
result[kDEFINES_KEY] = fromStringList(data.Defines);
|
||||||
}
|
}
|
||||||
|
|
||||||
result[kIS_GENERATED_KEY] = data.IsGenerated;
|
result[kIS_GENERATED_KEY] = data.IsGenerated;
|
||||||
@@ -691,21 +708,19 @@ static Json::Value DumpSourceFileGroup(const LanguageData& data,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Json::Value DumpSourceFilesList(
|
static void PopulateFileGroupData(
|
||||||
cmGeneratorTarget* target, const std::string& config,
|
cmGeneratorTarget* target, bool isInterfaceSources,
|
||||||
const std::map<std::string, LanguageData>& languageDataMap)
|
const std::vector<cmSourceFile*>& files, const std::string& config,
|
||||||
|
const std::map<std::string, LanguageData>& languageDataMap,
|
||||||
|
std::unordered_map<LanguageData, FileGroupSources>& fileGroups)
|
||||||
{
|
{
|
||||||
// Collect sourcefile groups:
|
|
||||||
|
|
||||||
std::vector<cmSourceFile*> files;
|
|
||||||
target->GetSourceFiles(files, config);
|
|
||||||
|
|
||||||
std::unordered_map<LanguageData, std::vector<std::string>> fileGroups;
|
|
||||||
for (cmSourceFile* file : files) {
|
for (cmSourceFile* file : files) {
|
||||||
LanguageData fileData;
|
LanguageData fileData;
|
||||||
fileData.Language = file->GetLanguage();
|
fileData.Language = file->GetLanguage();
|
||||||
if (!fileData.Language.empty()) {
|
if (!fileData.Language.empty() || isInterfaceSources) {
|
||||||
const LanguageData& ld = languageDataMap.at(fileData.Language);
|
const LanguageData& ld = isInterfaceSources
|
||||||
|
? languageDataMap.at(kInterfaceSourcesLanguageDataKey)
|
||||||
|
: languageDataMap.at(fileData.Language);
|
||||||
cmLocalGenerator* lg = target->GetLocalGenerator();
|
cmLocalGenerator* lg = target->GetLocalGenerator();
|
||||||
cmGeneratorExpressionInterpreter genexInterpreter(
|
cmGeneratorExpressionInterpreter genexInterpreter(
|
||||||
lg, target, config, target->GetName(), fileData.Language);
|
lg, target, config, target->GetName(), fileData.Language);
|
||||||
@@ -733,10 +748,14 @@ static Json::Value DumpSourceFilesList(
|
|||||||
lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file);
|
lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file);
|
||||||
|
|
||||||
for (const auto& include : includes) {
|
for (const auto& include : includes) {
|
||||||
|
// INTERFACE_LIBRARY targets do not support the
|
||||||
|
// IsSystemIncludeDirectory call so just set it to false.
|
||||||
|
const bool isSystemInclude = isInterfaceSources
|
||||||
|
? false
|
||||||
|
: target->IsSystemIncludeDirectory(include, config,
|
||||||
|
fileData.Language);
|
||||||
fileData.IncludePathList.push_back(
|
fileData.IncludePathList.push_back(
|
||||||
std::make_pair(include,
|
std::make_pair(include, isSystemInclude));
|
||||||
target->IsSystemIncludeDirectory(
|
|
||||||
include, config, fileData.Language)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,14 +784,71 @@ static Json::Value DumpSourceFilesList(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileData.IsGenerated = file->GetPropertyAsBool("GENERATED");
|
fileData.IsGenerated = file->GetPropertyAsBool("GENERATED");
|
||||||
std::vector<std::string>& groupFileList = fileGroups[fileData];
|
FileGroupSources& groupFileList = fileGroups[fileData];
|
||||||
groupFileList.push_back(file->GetFullPath());
|
groupFileList.IsInterfaceSources = isInterfaceSources;
|
||||||
|
groupFileList.Files.push_back(file->GetFullPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Json::Value DumpSourceFilesList(
|
||||||
|
cmGeneratorTarget* target, const std::string& config,
|
||||||
|
const std::map<std::string, LanguageData>& languageDataMap)
|
||||||
|
{
|
||||||
|
const cmStateEnums::TargetType type = target->GetType();
|
||||||
|
std::unordered_map<LanguageData, FileGroupSources> fileGroups;
|
||||||
|
|
||||||
|
// Collect sourcefile groups:
|
||||||
|
|
||||||
|
std::vector<cmSourceFile*> files;
|
||||||
|
if (type == cmStateEnums::INTERFACE_LIBRARY) {
|
||||||
|
// INTERFACE_LIBRARY targets do not create all the data structures
|
||||||
|
// associated with regular targets. If properties are explicitly specified
|
||||||
|
// for files in INTERFACE_SOURCES then we can get them through the Makefile
|
||||||
|
// rather than the target.
|
||||||
|
files = target->Makefile->GetSourceFiles();
|
||||||
|
} else {
|
||||||
|
target->GetSourceFiles(files, config);
|
||||||
|
PopulateFileGroupData(target, false /* isInterfaceSources */, files,
|
||||||
|
config, languageDataMap, fileGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect interface sourcefile groups:
|
||||||
|
|
||||||
|
auto targetProp = target->Target->GetProperty("INTERFACE_SOURCES");
|
||||||
|
if (targetProp != nullptr) {
|
||||||
|
cmGeneratorExpressionInterpreter genexInterpreter(
|
||||||
|
target->GetLocalGenerator(), target, config, target->GetName(), "");
|
||||||
|
|
||||||
|
auto evaluatedSources = cmsys::SystemTools::SplitString(
|
||||||
|
genexInterpreter.Evaluate(targetProp, "INTERFACE_SOURCES"), ';');
|
||||||
|
|
||||||
|
std::map<std::string, cmSourceFile*> filesMap;
|
||||||
|
for (auto file : files) {
|
||||||
|
filesMap[file->GetFullPath()] = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cmSourceFile*> interfaceSourceFiles;
|
||||||
|
for (const std::string& interfaceSourceFilePath : evaluatedSources) {
|
||||||
|
auto entry = filesMap.find(interfaceSourceFilePath);
|
||||||
|
if (entry != filesMap.end()) {
|
||||||
|
// use what we have since it has all the associated properties
|
||||||
|
interfaceSourceFiles.push_back(entry->second);
|
||||||
|
} else {
|
||||||
|
interfaceSourceFiles.push_back(
|
||||||
|
new cmSourceFile(target->Makefile, interfaceSourceFilePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PopulateFileGroupData(target, true /* isInterfaceSources */,
|
||||||
|
interfaceSourceFiles, config, languageDataMap,
|
||||||
|
fileGroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string baseDir = target->Makefile->GetCurrentSourceDirectory();
|
const std::string baseDir = target->Makefile->GetCurrentSourceDirectory();
|
||||||
Json::Value result = Json::arrayValue;
|
Json::Value result = Json::arrayValue;
|
||||||
for (auto const& it : fileGroups) {
|
for (auto const& it : fileGroups) {
|
||||||
Json::Value group = DumpSourceFileGroup(it.first, it.second, baseDir);
|
Json::Value group = DumpSourceFileGroup(
|
||||||
|
it.first, it.second.IsInterfaceSources, it.second.Files, baseDir);
|
||||||
if (!group.isNull()) {
|
if (!group.isNull()) {
|
||||||
result.append(group);
|
result.append(group);
|
||||||
}
|
}
|
||||||
@@ -883,6 +959,59 @@ static Json::Value DumpCTestConfigurationsList(const cmake* cm)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void GetTargetProperty(
|
||||||
|
cmGeneratorExpressionInterpreter& genexInterpreter,
|
||||||
|
cmGeneratorTarget* target, const char* propertyName,
|
||||||
|
std::vector<std::string>& propertyValue)
|
||||||
|
{
|
||||||
|
auto targetProp = target->Target->GetProperty(propertyName);
|
||||||
|
if (targetProp != nullptr) {
|
||||||
|
propertyValue = cmsys::SystemTools::SplitString(
|
||||||
|
genexInterpreter.Evaluate(targetProp, propertyName), ';');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CreateInterfaceSourcesEntry(
|
||||||
|
cmLocalGenerator* lg, cmGeneratorTarget* target, const std::string& config,
|
||||||
|
std::map<std::string, LanguageData>& languageDataMap)
|
||||||
|
{
|
||||||
|
LanguageData& ld = languageDataMap[kInterfaceSourcesLanguageDataKey];
|
||||||
|
ld.Language = "";
|
||||||
|
|
||||||
|
cmGeneratorExpressionInterpreter genexInterpreter(lg, target, config,
|
||||||
|
target->GetName(), "");
|
||||||
|
std::vector<std::string> propertyValue;
|
||||||
|
GetTargetProperty(genexInterpreter, target, "INTERFACE_INCLUDE_DIRECTORIES",
|
||||||
|
propertyValue);
|
||||||
|
for (std::string const& i : propertyValue) {
|
||||||
|
ld.IncludePathList.push_back(
|
||||||
|
std::make_pair(i, false /* isSystemInclude */));
|
||||||
|
}
|
||||||
|
|
||||||
|
propertyValue.clear();
|
||||||
|
GetTargetProperty(genexInterpreter, target,
|
||||||
|
"INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", propertyValue);
|
||||||
|
for (std::string const& i : propertyValue) {
|
||||||
|
ld.IncludePathList.push_back(
|
||||||
|
std::make_pair(i, true /* isSystemInclude */));
|
||||||
|
}
|
||||||
|
|
||||||
|
propertyValue.clear();
|
||||||
|
GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_OPTIONS",
|
||||||
|
propertyValue);
|
||||||
|
for (const auto& s : propertyValue) {
|
||||||
|
ld.Flags += " " + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
propertyValue.clear();
|
||||||
|
GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_DEFINITIONS",
|
||||||
|
propertyValue);
|
||||||
|
if (!propertyValue.empty()) {
|
||||||
|
std::set<std::string> defines(propertyValue.begin(), propertyValue.end());
|
||||||
|
ld.SetDefines(defines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Json::Value DumpTarget(cmGeneratorTarget* target,
|
static Json::Value DumpTarget(cmGeneratorTarget* target,
|
||||||
const std::string& config)
|
const std::string& config)
|
||||||
{
|
{
|
||||||
@@ -912,11 +1041,6 @@ static Json::Value DumpTarget(cmGeneratorTarget* target,
|
|||||||
result[kTYPE_KEY] = typeName;
|
result[kTYPE_KEY] = typeName;
|
||||||
result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory();
|
result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory();
|
||||||
result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory();
|
result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory();
|
||||||
|
|
||||||
if (type == cmStateEnums::INTERFACE_LIBRARY) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result[kFULL_NAME_KEY] = target->GetFullName(config);
|
result[kFULL_NAME_KEY] = target->GetFullName(config);
|
||||||
|
|
||||||
if (target->Target->GetHaveInstallRule()) {
|
if (target->Target->GetHaveInstallRule()) {
|
||||||
@@ -1003,8 +1127,22 @@ static Json::Value DumpTarget(cmGeneratorTarget* target,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> languages;
|
std::set<std::string> languages;
|
||||||
target->GetLanguages(languages, config);
|
|
||||||
std::map<std::string, LanguageData> languageDataMap;
|
std::map<std::string, LanguageData> languageDataMap;
|
||||||
|
if (type == cmStateEnums::INTERFACE_LIBRARY) {
|
||||||
|
// INTERFACE_LIBRARY targets do not create all the data structures
|
||||||
|
// associated with regular targets. If properties are explicitly specified
|
||||||
|
// for files in INTERFACE_SOURCES then we can get them through the Makefile
|
||||||
|
// rather than the target.
|
||||||
|
for (auto file : target->Makefile->GetSourceFiles()) {
|
||||||
|
const std::string& language = file->GetLanguage();
|
||||||
|
if (!language.empty()) {
|
||||||
|
languages.insert(language);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target->GetLanguages(languages, config);
|
||||||
|
}
|
||||||
|
|
||||||
for (std::string const& lang : languages) {
|
for (std::string const& lang : languages) {
|
||||||
LanguageData& ld = languageDataMap[lang];
|
LanguageData& ld = languageDataMap[lang];
|
||||||
ld.Language = lang;
|
ld.Language = lang;
|
||||||
@@ -1020,6 +1158,11 @@ static Json::Value DumpTarget(cmGeneratorTarget* target,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (target->Target->GetProperty("INTERFACE_SOURCES") != nullptr) {
|
||||||
|
// Create an entry in the languageDataMap for interface sources.
|
||||||
|
CreateInterfaceSourcesEntry(lg, target, config, languageDataMap);
|
||||||
|
}
|
||||||
|
|
||||||
Json::Value sourceGroupsValue =
|
Json::Value sourceGroupsValue =
|
||||||
DumpSourceFilesList(target, config, languageDataMap);
|
DumpSourceFilesList(target, config, languageDataMap);
|
||||||
if (!sourceGroupsValue.empty()) {
|
if (!sourceGroupsValue.empty()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user