Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #13043 (Added Support for Shared Items Projects) #6286

Merged
merged 34 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
cddfc16
Rebasing
Apr 19, 2024
51d8713
This change is crucial when $(SolutionDir) = "" and includePath is $(…
Mar 27, 2024
d4fb38a
Rebasing...
Apr 19, 2024
32cfcd1
Removing duplicate code, storing source files relative to the shared …
Apr 2, 2024
e7d69db
Proper error reporting instead of "exit(-1)" call
Apr 12, 2024
36a0f3e
Rebasing...
Apr 30, 2024
77a7dce
skipping string constructor
Apr 19, 2024
cdcd98f
Trying to fix up whitespace and formatting
Apr 19, 2024
a5cef0b
Even more formatting fixes
Apr 19, 2024
63853b2
Restoring TODO
Apr 19, 2024
07da987
Fixing up errors I introduced during rebasing, sorry!
Apr 19, 2024
4ea8d12
Restoring TODO and fixing whitespace
Apr 19, 2024
dd6b90b
More whitespace fixes...
Apr 19, 2024
a4ad8ae
Remove local stringReplace, adjust FileSettings usage
Apr 30, 2024
ed2a67a
Adding Solution containing Shared items project for test
Apr 30, 2024
a2cd83a
Rebasing...
Aug 9, 2024
433e041
Rebasing...
Aug 9, 2024
3164e05
Removing all but one configuration
Apr 30, 2024
a3c91fe
Undoing change (which fixed an issue locally, but is not related to s…
Jun 5, 2024
d648807
Fix whitespace formatting for formatter pipeline
Jun 5, 2024
f058b65
Rebasing...
Aug 9, 2024
c87a240
Fix issue: Reducing scope of variable
Jun 11, 2024
041a65b
Trying to appease the Pipeline
Jun 11, 2024
da70af9
Fix whitespace, hopefull fixing CI compilation error which works fine…
Jun 11, 2024
94ef315
Fixed formatting
Jun 12, 2024
8737362
Remove redundant {} initializer
Jun 12, 2024
341274d
Replacing exit with cleaner return
Jun 12, 2024
07a9ec8
Fixed missing "return", fixed trailing whitespace
Jun 12, 2024
7a24869
Fixed whitespace in test
Jun 12, 2024
7f84402
Reverting removal of init braces.
Jun 12, 2024
6374db1
Removing leftovers from rebasing
Aug 9, 2024
304519e
removal of unused test variables
Aug 9, 2024
e1c2280
fixed nits and blatant typo
Aug 19, 2024
1ebbf98
Fixed nits
Aug 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 117 additions & 8 deletions lib/importproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
}
} else if (endsWith(filename, ".vcxproj")) {
std::map<std::string, std::string, cppcheck::stricmp> variables;
if (importVcxproj(filename, variables, emptyString, fileFilters)) {
std::vector<SharedItemsProject> sharedItemsProjects;
if (importVcxproj(filename, variables, emptyString, fileFilters, sharedItemsProjects)) {
setRelativePaths(filename);
return ImportProject::Type::VS_VCXPROJ;
}
Expand Down Expand Up @@ -446,7 +447,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
variables["SolutionDir"] = path;

bool found = false;

std::vector<SharedItemsProject> sharedItemsProjects;
while (std::getline(istr,line)) {
if (!startsWith(line,"Project("))
continue;
Expand All @@ -461,7 +462,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
if (!Path::isAbsolute(vcxproj))
vcxproj = path + vcxproj;
vcxproj = Path::fromNativeSeparators(std::move(vcxproj));
if (!importVcxproj(vcxproj, variables, emptyString, fileFilters)) {
if (!importVcxproj(vcxproj, variables, emptyString, fileFilters, sharedItemsProjects)) {
printError("failed to load '" + vcxproj + "' from Visual Studio solution");
return false;
}
Expand Down Expand Up @@ -698,14 +699,15 @@ static void loadVisualStudioProperties(const std::string &props, std::map<std::s
}
}

bool ImportProject::importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters)
bool ImportProject::importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache)
DevFelixFaber marked this conversation as resolved.
Show resolved Hide resolved
{
variables["ProjectDir"] = Path::simplifyPath(Path::getPathFromFilename(filename));

std::list<ProjectConfiguration> projectConfigurationList;
std::list<std::string> compileList;
std::list<ItemDefinitionGroup> itemDefinitionGroupList;
std::string includePath;
std::vector<SharedItemsProject> sharedItemsProjects;

bool useOfMfc = false;

Expand Down Expand Up @@ -737,8 +739,10 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
for (const tinyxml2::XMLElement *e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "ClCompile") == 0) {
const char *include = e->Attribute("Include");
if (include && Path::acceptFile(include))
compileList.emplace_back(include);
if (include && Path::acceptFile(include)) {
std::string toInclude = Path::simplifyPath(Path::isAbsolute(include) ? include : Path::getPathFromFilename(filename) + include);
compileList.emplace_back(toInclude);
}
}
}
}
Expand All @@ -756,14 +760,54 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
loadVisualStudioProperties(projectAttribute, variables, includePath, additionalIncludeDirectories, itemDefinitionGroupList);
}
}
} else if (labelAttribute && std::strcmp(labelAttribute, "Shared") == 0) {
for (const tinyxml2::XMLElement *e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "Import") == 0) {
const char *projectAttribute = e->Attribute("Project");
if (projectAttribute) {
// Path to shared items project is relative to current project directory,
// unless the string starts with $(SolutionDir)
std::string pathToSharedItemsFile;
if (std::string(projectAttribute).rfind("$(SolutionDir)", 0) == 0) {
pathToSharedItemsFile = std::string(projectAttribute);
DevFelixFaber marked this conversation as resolved.
Show resolved Hide resolved
} else {
pathToSharedItemsFile = variables["ProjectDir"] + std::string(projectAttribute);
DevFelixFaber marked this conversation as resolved.
Show resolved Hide resolved
}
if (!simplifyPathWithVariables(pathToSharedItemsFile, variables)) {
printError("Could not simplify path to referenced shared items project");
return false;
}

SharedItemsProject toAdd = importVcxitems(pathToSharedItemsFile, fileFilters, cache);
if (!toAdd.successFull) {
printError("Could not load shared items project \"" + pathToSharedItemsFile + "\" from original path \"" + std::string(projectAttribute) + "\".");
return false;
}
sharedItemsProjects.emplace_back(toAdd);
}
}
}
}
}
}
// # TODO: support signedness of char via /J (and potential XML option for it)?
// we can only set it globally but in this context it needs to be treated per file

for (const std::string &c : compileList) {
const std::string cfilename = Path::simplifyPath(Path::isAbsolute(c) ? c : Path::getPathFromFilename(filename) + c);
// Include shared items project files
std::vector<std::string> sharedItemsIncludePaths;
for (const auto& sharedProject : sharedItemsProjects) {
for (const auto &file : sharedProject.sourceFiles) {
std::string pathToFile = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + file);
compileList.emplace_back(std::move(pathToFile));
}
for (const auto &p : sharedProject.includePaths) {
std::string path = Path::simplifyPath(Path::getPathFromFilename(sharedProject.pathToProjectFile) + p);
sharedItemsIncludePaths.emplace_back(std::move(path));
}
}

// Project files
for (const std::string &cfilename : compileList) {
if (!fileFilters.empty() && !matchglobs(fileFilters, cfilename))
continue;

Expand Down Expand Up @@ -809,13 +853,78 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
}
fsSetDefines(fs, fs.defines);
fsSetIncludePaths(fs, Path::getPathFromFilename(filename), toStringList(includePath + ';' + additionalIncludePaths), variables);
for (const auto &path : sharedItemsIncludePaths) {
fs.includePaths.emplace_back(path);
}
fileSettings.push_back(std::move(fs));
}
}

return true;
}

ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::string& filename, const std::vector<std::string>& fileFilters, std::vector<SharedItemsProject> &cache)
{
auto isInCacheCheck = [filename](const ImportProject::SharedItemsProject& e) -> bool {
return filename == e.pathToProjectFile;
};
auto iterator = std::find_if(cache.begin(), cache.end(), isInCacheCheck);
DevFelixFaber marked this conversation as resolved.
Show resolved Hide resolved
if (iterator != std::end(cache)) {
return *iterator;
}

SharedItemsProject result{};
DevFelixFaber marked this conversation as resolved.
Show resolved Hide resolved
result.pathToProjectFile = filename;

tinyxml2::XMLDocument doc;
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
if (error != tinyxml2::XML_SUCCESS) {
printError(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
return result;
}
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
if (rootnode == nullptr) {
printError("Visual Studio project file has no XML root node");
return result;
}
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
if (std::strcmp(node->Name(), "ItemGroup") == 0) {
for (const tinyxml2::XMLElement *e = node->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (std::strcmp(e->Name(), "ClCompile") == 0) {
const char* include = e->Attribute("Include");
if (include && Path::acceptFile(include)) {
std::string file(include);
findAndReplace(file, "$(MSBuildThisFileDirectory)", "./");

// Don't include file if it matches the filter
if (!fileFilters.empty() && !matchglobs(fileFilters, file))
continue;

result.sourceFiles.emplace_back(file);
} else {
printError("Could not find shared items source file");
return result;
}
}
}
} else if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) {
ItemDefinitionGroup temp(node, "");
for (const auto& includePath : toStringList(temp.additionalIncludePaths)) {
if (includePath == std::string("%(AdditionalIncludeDirectories)"))
DevFelixFaber marked this conversation as resolved.
Show resolved Hide resolved
continue;

std::string toAdd(includePath);
findAndReplace(toAdd, "$(MSBuildThisFileDirectory)", "./");
result.includePaths.emplace_back(toAdd);
}
}
}

result.successFull = true;
cache.emplace_back(result);
return result;
}

bool ImportProject::importBcb6Prj(const std::string &projectFilename)
{
tinyxml2::XMLDocument doc;
Expand Down
11 changes: 10 additions & 1 deletion lib/importproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,18 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
bool importCompileCommands(std::istream &istr);
bool importCppcheckGuiProject(std::istream &istr, Settings *settings);
virtual bool sourceFileExists(const std::string &file);

private:
struct SharedItemsProject {
bool successFull;
DevFelixFaber marked this conversation as resolved.
Show resolved Hide resolved
std::string pathToProjectFile;
std::vector<std::string> includePaths;
std::vector<std::string> sourceFiles;
};

bool importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
bool importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters);
static SharedItemsProject importVcxitems(const std::string &filename, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
bool importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
bool importBcb6Prj(const std::string &projectFilename);

static void printError(const std::string &message);
Expand Down
21 changes: 21 additions & 0 deletions test/cli/more-projects_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,3 +843,24 @@ def test_compdb_D(tmpdir):
assert stdout.splitlines() == out_expected
assert stderr.splitlines() == []
assert ret == 0, stdout


def test_shared_items_project(tmpdir = ""):
# tmpdir is unused
solutionDir = os.path.join(os.getcwd(), 'shared-items-project')
solutionFile = os.path.join(solutionDir, 'Solution.sln')

args = [
'--platform=win64',
'--project={}'.format(solutionFile),
'--project-configuration=Release|x64',
'-j1'
]

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0
lines = stdout.splitlines()

# Assume no errors, and that shared items code files have been checked as well
assert any('2/2 files checked 100% done' in x for x in lines)
assert stderr == ''
56 changes: 56 additions & 0 deletions test/cli/shared-items-project/Main/Main.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{074143a3-6080-409a-a181-24e4e468bfd8}</ProjectGuid>
<RootNamespace>Blub</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
<Import Project="$(SolutionDir)\Shared\Shared.vcxitems" Label="Shared" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="MainFile.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
7 changes: 7 additions & 0 deletions test/cli/shared-items-project/Main/MainFile.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <TestClass.h>

int main(void)
{
Shared::TestClass test{};
return 0;
}
22 changes: 22 additions & 0 deletions test/cli/shared-items-project/Shared/Shared.vcxitems
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<ItemsProjectGuid>{3633ee6f-e5e8-46fc-87c9-f13a18db966a}</ItemsProjectGuid>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)TestClass.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)TestClass.cpp" />
</ItemGroup>
</Project>
11 changes: 11 additions & 0 deletions test/cli/shared-items-project/Shared/TestClass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "TestClass.h"

using namespace Shared;

TestClass::TestClass()
{
}

TestClass::~TestClass()
{
}
11 changes: 11 additions & 0 deletions test/cli/shared-items-project/Shared/TestClass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

namespace Shared
{
class TestClass
{
public:
explicit TestClass();
virtual ~TestClass();
};
} // namespace Shared
28 changes: 28 additions & 0 deletions test/cli/shared-items-project/Solution.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34607.119
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Shared", "Shared\Shared.vcxitems", "{3633EE6F-E5E8-46FC-87C9-F13A18DB966A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Main", "Main\Main.vcxproj", "{074143A3-6080-409A-A181-24E4E468BFD8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{074143A3-6080-409A-A181-24E4E468BFD8}.Release|x64.ActiveCfg = Release|x64
{074143A3-6080-409A-A181-24E4E468BFD8}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {510D1526-E6EE-452F-A697-173A3D4C4E93}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
Shared\Shared.vcxitems*{074143a3-6080-409a-a181-24e4e468bfd8}*SharedItemsImports = 4
Shared\Shared.vcxitems*{3633ee6f-e5e8-46fc-87c9-f13a18db966a}*SharedItemsImports = 9
EndGlobalSection
EndGlobal
Loading