36
36
#include < stack>
37
37
#include < unordered_set>
38
38
#include < utility>
39
+ #include < vector>
39
40
40
41
#include " xml.h"
41
42
@@ -527,51 +528,11 @@ namespace {
527
528
std::string platformStr;
528
529
};
529
530
530
- struct ItemDefinitionGroup {
531
- explicit ItemDefinitionGroup (const tinyxml2::XMLElement *idg, std::string includePaths) : additionalIncludePaths(std::move(includePaths)) {
531
+ struct ConditionalGroup {
532
+ explicit ConditionalGroup (const tinyxml2::XMLElement *idg) {
532
533
const char *condAttr = idg->Attribute (" Condition" );
533
534
if (condAttr)
534
- condition = condAttr;
535
- for (const tinyxml2::XMLElement *e1 = idg->FirstChildElement (); e1 ; e1 = e1 ->NextSiblingElement ()) {
536
- const char * name = e1 ->Name ();
537
- if (std::strcmp (name, " ClCompile" ) == 0 ) {
538
- enhancedInstructionSet = " StreamingSIMDExtensions2" ;
539
- for (const tinyxml2::XMLElement *e = e1 ->FirstChildElement (); e; e = e->NextSiblingElement ()) {
540
- const char * const text = e->GetText ();
541
- if (!text)
542
- continue ;
543
- const char * const ename = e->Name ();
544
- if (std::strcmp (ename, " PreprocessorDefinitions" ) == 0 )
545
- preprocessorDefinitions = text;
546
- else if (std::strcmp (ename, " AdditionalIncludeDirectories" ) == 0 ) {
547
- if (!additionalIncludePaths.empty ())
548
- additionalIncludePaths += ' ;' ;
549
- additionalIncludePaths += text;
550
- } else if (std::strcmp (ename, " LanguageStandard" ) == 0 ) {
551
- if (std::strcmp (text, " stdcpp14" ) == 0 )
552
- cppstd = Standards::CPP14;
553
- else if (std::strcmp (text, " stdcpp17" ) == 0 )
554
- cppstd = Standards::CPP17;
555
- else if (std::strcmp (text, " stdcpp20" ) == 0 )
556
- cppstd = Standards::CPP20;
557
- else if (std::strcmp (text, " stdcpplatest" ) == 0 )
558
- cppstd = Standards::CPPLatest;
559
- } else if (std::strcmp (ename, " EnableEnhancedInstructionSet" ) == 0 ) {
560
- enhancedInstructionSet = text;
561
- }
562
- }
563
- }
564
- else if (std::strcmp (name, " Link" ) == 0 ) {
565
- for (const tinyxml2::XMLElement *e = e1 ->FirstChildElement (); e; e = e->NextSiblingElement ()) {
566
- const char * const text = e->GetText ();
567
- if (!text)
568
- continue ;
569
- if (std::strcmp (e->Name (), " EntryPointSymbol" ) == 0 ) {
570
- entryPointSymbol = text;
571
- }
572
- }
573
- }
574
- }
535
+ mCondition = condAttr;
575
536
}
576
537
577
538
static void replaceAll (std::string &c, const std::string &from, const std::string &to) {
@@ -585,9 +546,9 @@ namespace {
585
546
// see https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions
586
547
// properties are .NET String objects and you can call any of its members on them
587
548
bool conditionIsTrue (const ProjectConfiguration &p) const {
588
- if (condition .empty ())
549
+ if (mCondition .empty ())
589
550
return true ;
590
- std::string c = ' (' + condition + " );" ;
551
+ std::string c = ' (' + mCondition + " );" ;
591
552
replaceAll (c, " $(Configuration)" , p.configuration );
592
553
replaceAll (c, " $(Platform)" , p.platformStr );
593
554
@@ -623,13 +584,75 @@ namespace {
623
584
}
624
585
return false ;
625
586
}
626
- std::string condition;
587
+ private:
588
+ std::string mCondition ;
589
+ };
590
+
591
+ struct ItemDefinitionGroup : ConditionalGroup {
592
+ explicit ItemDefinitionGroup (const tinyxml2::XMLElement *idg, std::string includePaths) : ConditionalGroup(idg), additionalIncludePaths(std::move(includePaths)) {
593
+ for (const tinyxml2::XMLElement *e1 = idg->FirstChildElement (); e1 ; e1 = e1 ->NextSiblingElement ()) {
594
+ const char * name = e1 ->Name ();
595
+ if (std::strcmp (name, " ClCompile" ) == 0 ) {
596
+ enhancedInstructionSet = " StreamingSIMDExtensions2" ;
597
+ for (const tinyxml2::XMLElement *e = e1 ->FirstChildElement (); e; e = e->NextSiblingElement ()) {
598
+ const char * const text = e->GetText ();
599
+ if (!text)
600
+ continue ;
601
+ const char * const ename = e->Name ();
602
+ if (std::strcmp (ename, " PreprocessorDefinitions" ) == 0 )
603
+ preprocessorDefinitions = text;
604
+ else if (std::strcmp (ename, " AdditionalIncludeDirectories" ) == 0 ) {
605
+ if (!additionalIncludePaths.empty ())
606
+ additionalIncludePaths += ' ;' ;
607
+ additionalIncludePaths += text;
608
+ } else if (std::strcmp (ename, " LanguageStandard" ) == 0 ) {
609
+ if (std::strcmp (text, " stdcpp14" ) == 0 )
610
+ cppstd = Standards::CPP14;
611
+ else if (std::strcmp (text, " stdcpp17" ) == 0 )
612
+ cppstd = Standards::CPP17;
613
+ else if (std::strcmp (text, " stdcpp20" ) == 0 )
614
+ cppstd = Standards::CPP20;
615
+ else if (std::strcmp (text, " stdcpplatest" ) == 0 )
616
+ cppstd = Standards::CPPLatest;
617
+ } else if (std::strcmp (ename, " EnableEnhancedInstructionSet" ) == 0 ) {
618
+ enhancedInstructionSet = text;
619
+ }
620
+ }
621
+ }
622
+ else if (std::strcmp (name, " Link" ) == 0 ) {
623
+ for (const tinyxml2::XMLElement *e = e1 ->FirstChildElement (); e; e = e->NextSiblingElement ()) {
624
+ const char * const text = e->GetText ();
625
+ if (!text)
626
+ continue ;
627
+ if (std::strcmp (e->Name (), " EntryPointSymbol" ) == 0 ) {
628
+ entryPointSymbol = text;
629
+ }
630
+ }
631
+ }
632
+ }
633
+ }
634
+
627
635
std::string enhancedInstructionSet;
628
636
std::string preprocessorDefinitions;
629
637
std::string additionalIncludePaths;
630
638
std::string entryPointSymbol; // TODO: use this
631
639
Standards::cppstd_t cppstd = Standards::CPPLatest;
632
640
};
641
+
642
+ struct ConfigurationPropertyGroup : ConditionalGroup {
643
+ explicit ConfigurationPropertyGroup (const tinyxml2::XMLElement *idg) : ConditionalGroup(idg) {
644
+ for (const tinyxml2::XMLElement *e = idg->FirstChildElement (); e; e = e->NextSiblingElement ()) {
645
+ if (std::strcmp (e->Name (), " UseOfMfc" ) == 0 ) {
646
+ useOfMfc = true ;
647
+ } else if (std::strcmp (e->Name (), " CharacterSet" ) == 0 ) {
648
+ useUnicode = std::strcmp (e->GetText (), " Unicode" ) == 0 ;
649
+ }
650
+ }
651
+ }
652
+
653
+ bool useOfMfc = false ;
654
+ bool useUnicode = false ;
655
+ };
633
656
}
634
657
635
658
static std::list<std::string> toStringList (const std::string &s)
@@ -648,17 +671,8 @@ static std::list<std::string> toStringList(const std::string &s)
648
671
return ret;
649
672
}
650
673
651
- static void importPropertyGroup (const tinyxml2::XMLElement *node, std::map<std::string,std::string,cppcheck::stricmp> &variables, std::string &includePath, bool *useOfMfc )
674
+ static void importPropertyGroup (const tinyxml2::XMLElement *node, std::map<std::string, std::string, cppcheck::stricmp> &variables, std::string &includePath)
652
675
{
653
- if (useOfMfc) {
654
- for (const tinyxml2::XMLElement *e = node->FirstChildElement (); e; e = e->NextSiblingElement ()) {
655
- if (std::strcmp (e->Name (), " UseOfMfc" ) == 0 ) {
656
- *useOfMfc = true ;
657
- break ;
658
- }
659
- }
660
- }
661
-
662
676
const char * labelAttribute = node->Attribute (" Label" );
663
677
if (labelAttribute && std::strcmp (labelAttribute, " UserMacros" ) == 0 ) {
664
678
for (const tinyxml2::XMLElement *propertyGroup = node->FirstChildElement (); propertyGroup; propertyGroup = propertyGroup->NextSiblingElement ()) {
@@ -719,31 +733,39 @@ static void loadVisualStudioProperties(const std::string &props, std::map<std::s
719
733
}
720
734
}
721
735
} else if (std::strcmp (name," PropertyGroup" )==0 ) {
722
- importPropertyGroup (node, variables, includePath, nullptr );
736
+ importPropertyGroup (node, variables, includePath);
723
737
} else if (std::strcmp (name," ItemDefinitionGroup" )==0 ) {
724
738
itemDefinitionGroupList.emplace_back (node, additionalIncludeDirectories);
725
739
}
726
740
}
727
741
}
728
742
729
- 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)
743
+ bool ImportProject::importVcxproj (const std::string &filename,
744
+ std::map<std::string, std::string, cppcheck::stricmp> &variables,
745
+ const std::string &additionalIncludeDirectories,
746
+ const std::vector<std::string> &fileFilters,
747
+ std::vector<SharedItemsProject> &cache)
748
+ {
749
+ tinyxml2::XMLDocument doc;
750
+ const tinyxml2::XMLError error = doc.LoadFile (filename.c_str ());
751
+ if (error != tinyxml2::XML_SUCCESS) {
752
+ printError (std::string (" Visual Studio project file is not a valid XML - " ) + tinyxml2::XMLDocument::ErrorIDToName (error));
753
+ return false ;
754
+ }
755
+ return importVcxproj (filename, doc, variables, additionalIncludeDirectories, fileFilters, cache);
756
+ }
757
+
758
+ bool ImportProject::importVcxproj (const std::string &filename, const tinyxml2::XMLDocument &doc, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache)
730
759
{
731
760
variables[" ProjectDir" ] = Path::simplifyPath (Path::getPathFromFilename (filename));
732
761
733
762
std::list<ProjectConfiguration> projectConfigurationList;
734
763
std::list<std::string> compileList;
735
764
std::list<ItemDefinitionGroup> itemDefinitionGroupList;
765
+ std::vector<ConfigurationPropertyGroup> configurationPropertyGroups;
736
766
std::string includePath;
737
767
std::vector<SharedItemsProject> sharedItemsProjects;
738
768
739
- bool useOfMfc = false ;
740
-
741
- tinyxml2::XMLDocument doc;
742
- const tinyxml2::XMLError error = doc.LoadFile (filename.c_str ());
743
- if (error != tinyxml2::XML_SUCCESS) {
744
- printError (std::string (" Visual Studio project file is not a valid XML - " ) + tinyxml2::XMLDocument::ErrorIDToName (error));
745
- return false ;
746
- }
747
769
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement ();
748
770
if (rootnode == nullptr ) {
749
771
printError (" Visual Studio project file has no XML root node" );
@@ -777,7 +799,12 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
777
799
} else if (std::strcmp (name, " ItemDefinitionGroup" ) == 0 ) {
778
800
itemDefinitionGroupList.emplace_back (node, additionalIncludeDirectories);
779
801
} else if (std::strcmp (name, " PropertyGroup" ) == 0 ) {
780
- importPropertyGroup (node, variables, includePath, &useOfMfc);
802
+ const char * labelAttribute = node->Attribute (" Label" );
803
+ if (labelAttribute && std::strcmp (labelAttribute, " Configuration" ) == 0 ) {
804
+ configurationPropertyGroups.emplace_back (node);
805
+ } else {
806
+ importPropertyGroup (node, variables, includePath);
807
+ }
781
808
} else if (std::strcmp (name, " ImportGroup" ) == 0 ) {
782
809
const char *labelAttribute = node->Attribute (" Label" );
783
810
if (labelAttribute && std::strcmp (labelAttribute, " PropertySheets" ) == 0 ) {
@@ -853,7 +880,6 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
853
880
fs.cfg = p.name ;
854
881
// TODO: detect actual MSC version
855
882
fs.msc = true ;
856
- fs.useMfc = useOfMfc;
857
883
fs.defines = " _WIN32=1" ;
858
884
if (p.platform == ProjectConfiguration::Win32)
859
885
fs.platformType = Platform::Type::Win32W;
@@ -879,6 +905,17 @@ bool ImportProject::importVcxproj(const std::string &filename, std::map<std::str
879
905
fs.defines += " ;__AVX512__" ;
880
906
additionalIncludePaths += ' ;' + i.additionalIncludePaths ;
881
907
}
908
+ bool useUnicode = false ;
909
+ for (const ConfigurationPropertyGroup &c : configurationPropertyGroups) {
910
+ if (!c.conditionIsTrue (p))
911
+ continue ;
912
+ // in msbuild the last definition wins
913
+ useUnicode = c.useUnicode ;
914
+ fs.useMfc = c.useOfMfc ;
915
+ }
916
+ if (useUnicode) {
917
+ fs.defines += " ;UNICODE=1;_UNICODE=1" ;
918
+ }
882
919
fsSetDefines (fs, fs.defines );
883
920
fsSetIncludePaths (fs, Path::getPathFromFilename (filename), toStringList (includePath + ' ;' + additionalIncludePaths), variables);
884
921
for (const auto &path : sharedItemsIncludePaths) {
0 commit comments