@@ -203,7 +203,8 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
203203 }
204204 } else if (endsWith (filename, " .vcxproj" )) {
205205 std::map<std::string, std::string, cppcheck::stricmp> variables;
206- if (importVcxproj (filename, variables, emptyString, fileFilters)) {
206+ std::vector<SharedItemsProject> sharedItemsProjects;
207+ if (importVcxproj (filename, variables, emptyString, fileFilters, sharedItemsProjects)) {
207208 setRelativePaths (filename);
208209 return ImportProject::Type::VS_VCXPROJ;
209210 }
@@ -446,7 +447,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
446447 variables[" SolutionDir" ] = path;
447448
448449 bool found = false ;
449-
450+ std::vector<SharedItemsProject> sharedItemsProjects;
450451 while (std::getline (istr,line)) {
451452 if (!startsWith (line," Project(" ))
452453 continue ;
@@ -461,7 +462,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
461462 if (!Path::isAbsolute (vcxproj))
462463 vcxproj = path + vcxproj;
463464 vcxproj = Path::fromNativeSeparators (std::move (vcxproj));
464- if (!importVcxproj (vcxproj, variables, emptyString, fileFilters)) {
465+ if (!importVcxproj (vcxproj, variables, emptyString, fileFilters, sharedItemsProjects )) {
465466 printError (" failed to load '" + vcxproj + " ' from Visual Studio solution" );
466467 return false ;
467468 }
@@ -698,14 +699,15 @@ static void loadVisualStudioProperties(const std::string &props, std::map<std::s
698699 }
699700}
700701
701- 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)
702+ 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 )
702703{
703704 variables[" ProjectDir" ] = Path::simplifyPath (Path::getPathFromFilename (filename));
704705
705706 std::list<ProjectConfiguration> projectConfigurationList;
706707 std::list<std::string> compileList;
707708 std::list<ItemDefinitionGroup> itemDefinitionGroupList;
708709 std::string includePath;
710+ std::vector<SharedItemsProject> sharedItemsProjects;
709711
710712 bool useOfMfc = false ;
711713
@@ -737,8 +739,10 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
737739 for (const tinyxml2::XMLElement *e = node->FirstChildElement (); e; e = e->NextSiblingElement ()) {
738740 if (std::strcmp (e->Name (), " ClCompile" ) == 0 ) {
739741 const char *include = e->Attribute (" Include" );
740- if (include && Path::acceptFile (include))
741- compileList.emplace_back (include);
742+ if (include && Path::acceptFile (include)) {
743+ std::string toInclude = Path::simplifyPath (Path::isAbsolute (include) ? include : Path::getPathFromFilename (filename) + include);
744+ compileList.emplace_back (toInclude);
745+ }
742746 }
743747 }
744748 }
@@ -756,14 +760,54 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
756760 loadVisualStudioProperties (projectAttribute, variables, includePath, additionalIncludeDirectories, itemDefinitionGroupList);
757761 }
758762 }
763+ } else if (labelAttribute && std::strcmp (labelAttribute, " Shared" ) == 0 ) {
764+ for (const tinyxml2::XMLElement *e = node->FirstChildElement (); e; e = e->NextSiblingElement ()) {
765+ if (std::strcmp (e->Name (), " Import" ) == 0 ) {
766+ const char *projectAttribute = e->Attribute (" Project" );
767+ if (projectAttribute) {
768+ // Path to shared items project is relative to current project directory,
769+ // unless the string starts with $(SolutionDir)
770+ std::string pathToSharedItemsFile;
771+ if (std::string (projectAttribute).rfind (" $(SolutionDir)" , 0 ) == 0 ) {
772+ pathToSharedItemsFile = projectAttribute;
773+ } else {
774+ pathToSharedItemsFile = variables[" ProjectDir" ] + projectAttribute;
775+ }
776+ if (!simplifyPathWithVariables (pathToSharedItemsFile, variables)) {
777+ printError (" Could not simplify path to referenced shared items project" );
778+ return false ;
779+ }
780+
781+ SharedItemsProject toAdd = importVcxitems (pathToSharedItemsFile, fileFilters, cache);
782+ if (!toAdd.successful ) {
783+ printError (" Could not load shared items project \" " + pathToSharedItemsFile + " \" from original path \" " + std::string (projectAttribute) + " \" ." );
784+ return false ;
785+ }
786+ sharedItemsProjects.emplace_back (toAdd);
787+ }
788+ }
789+ }
759790 }
760791 }
761792 }
762793 // # TODO: support signedness of char via /J (and potential XML option for it)?
763794 // we can only set it globally but in this context it needs to be treated per file
764795
765- for (const std::string &c : compileList) {
766- const std::string cfilename = Path::simplifyPath (Path::isAbsolute (c) ? c : Path::getPathFromFilename (filename) + c);
796+ // Include shared items project files
797+ std::vector<std::string> sharedItemsIncludePaths;
798+ for (const auto & sharedProject : sharedItemsProjects) {
799+ for (const auto &file : sharedProject.sourceFiles ) {
800+ std::string pathToFile = Path::simplifyPath (Path::getPathFromFilename (sharedProject.pathToProjectFile ) + file);
801+ compileList.emplace_back (std::move (pathToFile));
802+ }
803+ for (const auto &p : sharedProject.includePaths ) {
804+ std::string path = Path::simplifyPath (Path::getPathFromFilename (sharedProject.pathToProjectFile ) + p);
805+ sharedItemsIncludePaths.emplace_back (std::move (path));
806+ }
807+ }
808+
809+ // Project files
810+ for (const std::string &cfilename : compileList) {
767811 if (!fileFilters.empty () && !matchglobs (fileFilters, cfilename))
768812 continue ;
769813
@@ -809,13 +853,78 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
809853 }
810854 fsSetDefines (fs, fs.defines );
811855 fsSetIncludePaths (fs, Path::getPathFromFilename (filename), toStringList (includePath + ' ;' + additionalIncludePaths), variables);
856+ for (const auto &path : sharedItemsIncludePaths) {
857+ fs.includePaths .emplace_back (path);
858+ }
812859 fileSettings.push_back (std::move (fs));
813860 }
814861 }
815862
816863 return true ;
817864}
818865
866+ ImportProject::SharedItemsProject ImportProject::importVcxitems (const std::string& filename, const std::vector<std::string>& fileFilters, std::vector<SharedItemsProject> &cache)
867+ {
868+ auto isInCacheCheck = [filename](const ImportProject::SharedItemsProject& e) -> bool {
869+ return filename == e.pathToProjectFile ;
870+ };
871+ const auto iterator = std::find_if (cache.begin (), cache.end (), isInCacheCheck);
872+ if (iterator != std::end (cache)) {
873+ return *iterator;
874+ }
875+
876+ SharedItemsProject result;
877+ result.pathToProjectFile = filename;
878+
879+ tinyxml2::XMLDocument doc;
880+ const tinyxml2::XMLError error = doc.LoadFile (filename.c_str ());
881+ if (error != tinyxml2::XML_SUCCESS) {
882+ printError (std::string (" Visual Studio project file is not a valid XML - " ) + tinyxml2::XMLDocument::ErrorIDToName (error));
883+ return result;
884+ }
885+ const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement ();
886+ if (rootnode == nullptr ) {
887+ printError (" Visual Studio project file has no XML root node" );
888+ return result;
889+ }
890+ for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement (); node; node = node->NextSiblingElement ()) {
891+ if (std::strcmp (node->Name (), " ItemGroup" ) == 0 ) {
892+ for (const tinyxml2::XMLElement *e = node->FirstChildElement (); e; e = e->NextSiblingElement ()) {
893+ if (std::strcmp (e->Name (), " ClCompile" ) == 0 ) {
894+ const char * include = e->Attribute (" Include" );
895+ if (include && Path::acceptFile (include)) {
896+ std::string file (include);
897+ findAndReplace (file, " $(MSBuildThisFileDirectory)" , " ./" );
898+
899+ // Don't include file if it matches the filter
900+ if (!fileFilters.empty () && !matchglobs (fileFilters, file))
901+ continue ;
902+
903+ result.sourceFiles .emplace_back (file);
904+ } else {
905+ printError (" Could not find shared items source file" );
906+ return result;
907+ }
908+ }
909+ }
910+ } else if (std::strcmp (node->Name (), " ItemDefinitionGroup" ) == 0 ) {
911+ ItemDefinitionGroup temp (node, " " );
912+ for (const auto & includePath : toStringList (temp.additionalIncludePaths )) {
913+ if (includePath == " %(AdditionalIncludeDirectories)" )
914+ continue ;
915+
916+ std::string toAdd (includePath);
917+ findAndReplace (toAdd, " $(MSBuildThisFileDirectory)" , " ./" );
918+ result.includePaths .emplace_back (toAdd);
919+ }
920+ }
921+ }
922+
923+ result.successful = true ;
924+ cache.emplace_back (result);
925+ return result;
926+ }
927+
819928bool ImportProject::importBcb6Prj (const std::string &projectFilename)
820929{
821930 tinyxml2::XMLDocument doc;
0 commit comments