From 3e7aa5cfdeb2721da1b291f76ecd302f7890edfe Mon Sep 17 00:00:00 2001 From: Ivan Shakhov Date: Fri, 27 Mar 2026 21:49:44 +0100 Subject: [PATCH 1/6] allow sln/vcxproj with Apple platform --- Sharpmake.Generators/GeneratorManager.cs | 77 ++++++++----------- .../Apple/BaseApplePlatform.cs | 40 +++++----- .../HelloXCode.CommonProject.sharpmake.cs | 5 +- .../HelloXCode.CommonTarget.sharpmake.cs | 44 +++++++---- 4 files changed, 81 insertions(+), 85 deletions(-) diff --git a/Sharpmake.Generators/GeneratorManager.cs b/Sharpmake.Generators/GeneratorManager.cs index 940a155a2..5f5eb7e24 100644 --- a/Sharpmake.Generators/GeneratorManager.cs +++ b/Sharpmake.Generators/GeneratorManager.cs @@ -120,56 +120,43 @@ public void Generate(Builder builder, } public void Generate(Builder builder, - Solution solution, - List configurations, - string solutionFile, - List generatedFiles, - List skipFiles) + Solution solution, + List configurations, + string solutionFile, + List generatedFiles, + List skipFiles) { - if (configurations[0].Platform == Platform.ios || - configurations[0].Platform == Platform.mac || - configurations[0].Platform == Platform.tvos || - configurations[0].Platform == Platform.watchos || - configurations[0].Platform == Platform.maccatalyst - ) + if (UtilityMethods.HasFastBuildConfig(configurations)) { - XCWorkspaceGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - if (UtilityMethods.HasFastBuildConfig(configurations)) - { - MasterBffGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - } + MasterBffGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); } - else + + var devEnv = configurations[0].Target.GetFragment(); + switch (devEnv) { - DevEnv devEnv = configurations[0].Target.GetFragment(); - switch (devEnv) + case DevEnv.xcode: + XCWorkspaceGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + break; + case DevEnv.make: { - case DevEnv.make: - { - if (configurations[0].Platform == Platform.android) - MakeApplicationGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - else - MakefileGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - break; - } - case DevEnv.vs2015: - case DevEnv.vs2017: - case DevEnv.vs2019: - case DevEnv.vs2022: - case DevEnv.vs2026: - { - if (UtilityMethods.HasFastBuildConfig(configurations)) - { - MasterBffGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - } - - SlnGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - break; - } - default: - { - throw new Error("Generate called with unknown DevEnv: " + devEnv); - } + if (configurations[0].Platform == Platform.android) + MakeApplicationGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + else + MakefileGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + break; + } + case DevEnv.vs2015: + case DevEnv.vs2017: + case DevEnv.vs2019: + case DevEnv.vs2022: + case DevEnv.vs2026: + { + SlnGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + break; + } + default: + { + throw new Error("Generate called with unknown DevEnv: " + devEnv); } } } diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs index 750e63de1..8f35428a5 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs @@ -1456,7 +1456,7 @@ public virtual void SelectLinkerOptions(IGenerationContext context) public void SelectPlatformAdditionalDependenciesOptions(IGenerationContext context) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void SelectApplicationFormatOptions(IGenerationContext context) @@ -1469,7 +1469,7 @@ public void SelectBuildType(IGenerationContext context) public virtual void SelectPreprocessorDefinitionsVcxproj(IVcxprojGenerationContext context) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public bool HasPrecomp(IGenerationContext context) @@ -1479,92 +1479,92 @@ public bool HasPrecomp(IGenerationContext context) public void GenerateSdkVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateMakefileConfigurationVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectCompileVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectLinkVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectMasmVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectNasmVcxproj(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateUserConfigurationFile(Project.Configuration conf, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateRunFromPcDeployment(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GeneratePlatformSpecificProjectDescription(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectPlatformSdkDirectoryDescription(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GeneratePostDefaultPropsImport(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectConfigurationGeneral(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectConfigurationGeneral2(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectConfigurationFastBuildMakeFile(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectConfigurationCustomMakeFile(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GenerateProjectPlatformImportSheet(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GeneratePlatformResourceFileList(IVcxprojGenerationContext context, IFileGenerator generator, Strings alreadyWrittenPriFiles, IList resourceFiles, IList imageResourceFiles) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } public void GeneratePlatformReferences(IVcxprojGenerationContext context, IFileGenerator generator) { - throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } // type -> files diff --git a/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs b/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs index 94c8636bb..4b9ef0ac5 100644 --- a/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs +++ b/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs @@ -41,6 +41,8 @@ public virtual void ConfigureAll(Configuration conf, CommonTarget target) conf.ProjectFileName = "[project.Name]_[target.Platform]"; if (target.DevEnv != DevEnv.xcode) conf.ProjectFileName += "_[target.DevEnv]"; + if (target.BuildSystem == BuildSystem.FastBuild) + conf.ProjectFileName += "_FastBuild"; conf.ProjectPath = Path.Combine(Globals.TmpDirectory, @"projects\[project.Name]"); conf.IsFastBuild = target.BuildSystem == BuildSystem.FastBuild; @@ -118,9 +120,6 @@ public virtual void BlobNoBlob(Configuration conf, CommonTarget target) { conf.FastBuildBlobbed = false; conf.IsBlobbed = false; - - if (conf.IsFastBuild) - conf.ProjectName += "_NoBlob"; } #endregion //////////////////////////////////////////////////////////////////////// diff --git a/samples/HelloXCode/HelloXCode.CommonTarget.sharpmake.cs b/samples/HelloXCode/HelloXCode.CommonTarget.sharpmake.cs index b54b1775b..453d328ea 100644 --- a/samples/HelloXCode/HelloXCode.CommonTarget.sharpmake.cs +++ b/samples/HelloXCode/HelloXCode.CommonTarget.sharpmake.cs @@ -57,21 +57,27 @@ public override string Name nameParts.Add(Optimization.ToString().ToLowerInvariant()); if (BuildSystem == BuildSystem.FastBuild) nameParts.Add(BuildSystem.ToString().ToLowerInvariant()); + + if (Blob == Blob.Blob) + nameParts.Add(Blob.ToString().ToLowerInvariant()); return string.Join("_", nameParts); } } - + public string SolutionPlatformName { get { var nameParts = new List(); - nameParts.Add(BuildSystem.ToString()); - - if (BuildSystem == BuildSystem.FastBuild && Blob == Blob.NoBlob) - nameParts.Add(Blob.ToString()); + if (BuildSystem == BuildSystem.FastBuild) + nameParts.Add(BuildSystem.ToString().ToLowerInvariant()); + + if (Blob == Blob.Blob) + nameParts.Add(Blob.ToString().ToLowerInvariant()); + + nameParts.Add(DevEnv.ToString().ToLowerInvariant()); return string.Join("_", nameParts); } @@ -92,8 +98,7 @@ public string DirectoryName if (BuildSystem == BuildSystem.FastBuild) dirNameParts.Add(BuildSystem.ToString()); - if (DevEnv != DevEnv.xcode) - dirNameParts.Add(DevEnv.ToString()); + dirNameParts.Add(DevEnv.ToString()); return string.Join("_", dirNameParts).ToLowerInvariant(); } @@ -115,7 +120,7 @@ public static CommonTarget[] GetMacTargets() { var macosTarget = new CommonTarget( Platform.mac, - DevEnv.xcode, + DevEnv.xcode | DevEnv.vs2026, Optimization.Debug | Optimization.Release, Blob.NoBlob, BuildSystem.Default @@ -129,12 +134,13 @@ public static CommonTarget[] GetMacTargets() // make a fastbuild version of the target var macosFastBuildTarget = (CommonTarget)macosTarget.Clone( Blob.FastBuildUnitys, - BuildSystem.FastBuild + BuildSystem.FastBuild, + DevEnv.vs2026 ); var iosTarget = new CommonTarget( Platform.ios, - DevEnv.xcode, + DevEnv.xcode | DevEnv.vs2026, Optimization.Debug | Optimization.Release, Blob.NoBlob, BuildSystem.Default @@ -148,12 +154,13 @@ public static CommonTarget[] GetMacTargets() // make a fastbuild version of the target var iosFastBuildTarget = (CommonTarget)iosTarget.Clone( Blob.FastBuildUnitys, - BuildSystem.FastBuild + BuildSystem.FastBuild, + DevEnv.vs2026 ); var tvosTarget = new CommonTarget( Platform.tvos, - DevEnv.xcode, + DevEnv.xcode | DevEnv.vs2026, Optimization.Debug | Optimization.Release, Blob.NoBlob, BuildSystem.Default @@ -167,12 +174,13 @@ public static CommonTarget[] GetMacTargets() // make a fastbuild version of the target var tvosFastBuildTarget = (CommonTarget)tvosTarget.Clone( Blob.FastBuildUnitys, - BuildSystem.FastBuild + BuildSystem.FastBuild, + DevEnv.vs2026 ); var watchosTarget = new CommonTarget( Platform.watchos, - DevEnv.xcode, + DevEnv.xcode | DevEnv.vs2026, Optimization.Debug | Optimization.Release, Blob.NoBlob, BuildSystem.Default @@ -186,12 +194,13 @@ public static CommonTarget[] GetMacTargets() // make a fastbuild version of the target var watchosFastBuildTarget = (CommonTarget)watchosTarget.Clone( Blob.FastBuildUnitys, - BuildSystem.FastBuild + BuildSystem.FastBuild, + DevEnv.vs2026 ); var catalystTarget = new CommonTarget( Platform.maccatalyst, - DevEnv.xcode, + DevEnv.xcode | DevEnv.vs2026, Optimization.Debug | Optimization.Release, Blob.NoBlob, BuildSystem.Default @@ -205,7 +214,8 @@ public static CommonTarget[] GetMacTargets() // make a FastBuild version of the target var catalystFastBuildTarget = (CommonTarget)catalystTarget.Clone( Blob.FastBuildUnitys, - BuildSystem.FastBuild + BuildSystem.FastBuild, + DevEnv.vs2026 ); return new[] { From bd5b68b664cdf50521b081cd298df9c950d46815 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 07:49:56 +0000 Subject: [PATCH 2/6] Fix Apple platform vcxproj: skip MSVC imports, add clang system include paths Co-authored-by: van800 <1482681+van800@users.noreply.github.com> --- .../VisualStudio/IPlatformVcxproj.cs | 3 + .../VisualStudio/Vcxproj.Template.cs | 14 ++- Sharpmake.Generators/VisualStudio/Vcxproj.cs | 21 +++- .../Apple/BaseApplePlatform.cs | 106 +++++++++++++++++- .../Apple/MacCatalystPlatform.cs | 2 + .../Apple/MacOsPlatform.cs | 2 + .../Apple/iOsPlatform.cs | 2 + .../Apple/tvOsPlatform.cs | 2 + .../Apple/watchOsPlatform.cs | 2 + .../Sharpmake.CommonPlatforms/BasePlatform.cs | 1 + 10 files changed, 144 insertions(+), 11 deletions(-) diff --git a/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs b/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs index 88ad869e1..8f6e96db1 100644 --- a/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/IPlatformVcxproj.cs @@ -41,6 +41,9 @@ public interface IPlatformVcxproj bool HasUserAccountControlSupport { get; } bool HasEditAndContinueDebuggingSupport { get; } + // When false, the generator will skip the standard Microsoft.Cpp.*.props/targets imports. + bool IsMSVC { get; } + IEnumerable GetImplicitlyDefinedSymbols(IGenerationContext context); IEnumerable GetLibraryPaths(IGenerationContext context); diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs index 2a323a547..7714923e5 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs @@ -88,9 +88,12 @@ public static class Project public static string ProjectEnd = @""; - public static string ProjectAfterConfigurationsGeneral = + public static string MicrosoftCppProps = @" - +"; + + public static string ProjectAfterConfigurationsGeneral = +@" "; public static string ProjectAfterConfigurationsGeneralImportPropertySheets = @" @@ -138,9 +141,12 @@ public static class Project @" "; - public static string ProjectTargetsBegin = + public static string ImportMicrosoftCppTargets = @" - +"; + + public static string ProjectTargetsBegin = +@" "; public static string ProjectTargetsItem = diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index c902a17ca..ba7c91fe7 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -467,7 +467,9 @@ private void GenerateImpl(GenerationContext context, IList generatedFile foreach (var platform in context.PresentPlatforms.Values) platform.GenerateProjectPlatformSdkDirectoryDescription(context, fileGenerator); - fileGenerator.Write(Template.Project.ImportCppDefaultProps); + bool isMSVC = context.PresentPlatforms.Values.Any(p => p.IsMSVC); + if (isMSVC) + fileGenerator.Write(Template.Project.ImportCppDefaultProps); foreach (var platform in context.PresentPlatforms.Values) platform.GeneratePostDefaultPropsImport(context, fileGenerator); @@ -495,6 +497,8 @@ private void GenerateImpl(GenerationContext context, IList generatedFile } // .props files + if (isMSVC) + fileGenerator.Write(Template.Project.MicrosoftCppProps); fileGenerator.Write(Template.Project.ProjectAfterConfigurationsGeneral); if (context.Project.ContainsASM) { @@ -671,10 +675,13 @@ private void GenerateImpl(GenerationContext context, IList generatedFile // .targets files { + if (isMSVC) + fileGenerator.Write(Template.Project.ImportMicrosoftCppTargets); fileGenerator.Write(Template.Project.ProjectTargetsBegin); if (context.Project.ContainsASM) { - fileGenerator.Write(Template.Project.ProjectMasmTargetsItem); + if (isMSVC) + fileGenerator.Write(Template.Project.ProjectMasmTargetsItem); } if (context.Project.ContainsNASM) { @@ -682,9 +689,12 @@ private void GenerateImpl(GenerationContext context, IList generatedFile { throw new ArgumentNullException("NasmExePath not set and needed for NASM assembly files."); } - using (fileGenerator.Declare("importedNasmTargetsFile", context.Project.NasmTargetsFile)) + if (isMSVC) { - fileGenerator.Write(Template.Project.ProjectNasmTargetsItem); + using (fileGenerator.Declare("importedNasmTargetsFile", context.Project.NasmTargetsFile)) + { + fileGenerator.Write(Template.Project.ProjectNasmTargetsItem); + } } } @@ -780,7 +790,8 @@ private static void FillIncludeDirectoriesOptions(GenerationContext context) context.Options["AdditionalPlatformIncludeDirectories"] = platformIncludePaths.Any() ? Util.PathGetRelative(context.ProjectDirectory, platformIncludePaths).JoinStrings(";") : FileGeneratorUtilities.RemoveLineTag; var nmakeIncludeSearchPath = includePaths.Concat(platformIncludePaths); - context.Options["NMakeIncludeSearchPath"] = nmakeIncludeSearchPath.Any() ? Util.PathGetRelative(context.ProjectDirectory, nmakeIncludeSearchPath).JoinStrings(";") : FileGeneratorUtilities.RemoveLineTag; + + context.Options["NMakeIncludeSearchPath"] = nmakeIncludeSearchPath.Any() ? string.Join(";", nmakeIncludeSearchPath) : FileGeneratorUtilities.RemoveLineTag; // Fill resource include dirs var resourceIncludePaths = platformVcxproj.GetResourceIncludePaths(context); diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs index 8f35428a5..1ae788c04 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using Sharpmake.Generators; @@ -566,6 +567,100 @@ public void SetupStaticLibraryPaths(Project.Configuration configuration, Depende public bool ExcludesPrecompiledHeadersFromBuild => false; public bool HasUserAccountControlSupport => false; public bool HasEditAndContinueDebuggingSupport => false; + public bool IsMSVC => false; + + // The xcrun SDK name for this platform, e.g. "iphoneos", "macosx", "appletvos", "watchos" + protected abstract string XcrunSdkName { get; } + + private static readonly Dictionary> s_clangSystemIncludeCache = new Dictionary>(); + private static readonly object s_clangSystemIncludeCacheLock = new object(); + + private static IReadOnlyList GetClangSystemIncludePathsForSdk(string sdkName) + { + lock (s_clangSystemIncludeCacheLock) + { + if (s_clangSystemIncludeCache.TryGetValue(sdkName, out var cached)) + return cached; + + var result = new List(); + try + { + // Get the SDK path via xcrun + string sdkPath = RunProcessAndGetOutput("xcrun", $"--sdk {sdkName} --show-sdk-path").Trim(); + if (!string.IsNullOrEmpty(sdkPath)) + { + // Run clang to get the system include paths + string clangOutput = RunProcessAndGetOutput( + "clang++", + $"-v -E -x c++ /dev/null -isysroot \"{sdkPath}\"", + redirectStdErr: true + ); + + bool inSearchList = false; + foreach (string line in clangOutput.Split('\n')) + { + if (line.TrimEnd() == "#include <...> search starts here:") + { + inSearchList = true; + continue; + } + if (line.TrimEnd() == "End of search list.") + { + inSearchList = false; + continue; + } + if (inSearchList) + { + // Lines look like " /path/to/dir" or " /path/to/dir (framework directory)" + string path = line.Trim(); + int parenIdx = path.IndexOf(" (", StringComparison.Ordinal); + if (parenIdx >= 0) + path = path.Substring(0, parenIdx).TrimEnd(); + if (!string.IsNullOrEmpty(path)) + result.Add(path); + } + } + } + } + catch (Exception ex) + { + // If xcrun or clang++ is not available (e.g., not on macOS), return empty list + Trace.TraceWarning($"[Sharpmake] Could not discover system include paths for SDK '{sdkName}': {ex.Message}"); + } + + IReadOnlyList readOnly = result.AsReadOnly(); + s_clangSystemIncludeCache[sdkName] = readOnly; + return readOnly; + } + } + + private static string RunProcessAndGetOutput(string executable, string arguments, bool redirectStdErr = false) + { + var psi = new ProcessStartInfo + { + FileName = executable, + Arguments = arguments, + RedirectStandardOutput = true, + RedirectStandardError = redirectStdErr, + UseShellExecute = false, + CreateNoWindow = true + }; + + using (var process = Process.Start(psi)) + { + if (process == null) + { + Trace.TraceWarning($"[Sharpmake] Failed to start process: {executable} {arguments}"); + return string.Empty; + } + + string output = process.StandardOutput.ReadToEnd(); + string errOutput = redirectStdErr ? process.StandardError.ReadToEnd() : string.Empty; + process.WaitForExit(); + + return redirectStdErr ? output + errOutput : output; + } + } public IEnumerable GetImplicitlyDefinedSymbols(IGenerationContext context) { @@ -601,7 +696,8 @@ public IEnumerable GetIncludePaths(IGenerationContext context) } public IEnumerable GetPlatformIncludePaths(IGenerationContext context) { - return GetPlatformIncludePathsWithPrefixImpl(context).Select(x => x.Path); + return GetPlatformIncludePathsWithPrefixImpl(context).Select(x => x.Path) + .Concat(GetClangSystemIncludePathsForSdk(XcrunSdkName)); } public IEnumerable GetPlatformIncludePathsWithPrefix(IGenerationContext context) { @@ -1537,9 +1633,15 @@ public void GenerateProjectConfigurationGeneral(IVcxprojGenerationContext contex // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); } + private const string _projectConfigurationsGeneral2 = + @" + [options.NMakeIncludeSearchPath] + +"; + public void GenerateProjectConfigurationGeneral2(IVcxprojGenerationContext context, IFileGenerator generator) { - // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + generator.Write(_projectConfigurationsGeneral2); } public void GenerateProjectConfigurationFastBuildMakeFile(IVcxprojGenerationContext context, IFileGenerator generator) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacCatalystPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacCatalystPlatform.cs index 49a96dd36..48aa47e95 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacCatalystPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacCatalystPlatform.cs @@ -26,6 +26,8 @@ public sealed partial class MacCatalystPlatform : BaseApplePlatform public override string SimplePlatformString => "MacCatalyst"; // "Mac Catalyst" is the actual name #endregion + protected override string XcrunSdkName => "macosx"; + #region IPlatformBff implementation public override string BffPlatformDefine => "_MACCATALYST"; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacOsPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacOsPlatform.cs index c11fd7e92..6e5c1757b 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacOsPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/MacOsPlatform.cs @@ -25,6 +25,8 @@ public sealed class MacOsPlatform : BaseApplePlatform public override string SimplePlatformString => "macOS"; #endregion + protected override string XcrunSdkName => "macosx"; + #region IPlatformBff implementation public override string BffPlatformDefine => "APPLE_OSX"; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/iOsPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/iOsPlatform.cs index f806f8df9..193a1cf62 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/iOsPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/iOsPlatform.cs @@ -26,6 +26,8 @@ public sealed partial class iOsPlatform : BaseApplePlatform public override string SimplePlatformString => "iOS"; #endregion + protected override string XcrunSdkName => "iphoneos"; + #region IPlatformBff implementation public override string BffPlatformDefine => "_IOS"; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/tvOsPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/tvOsPlatform.cs index 61c411532..e8de19784 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/tvOsPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/tvOsPlatform.cs @@ -25,6 +25,8 @@ public sealed partial class tvOsPlatform : BaseApplePlatform public override string SimplePlatformString => "tvOS"; #endregion + protected override string XcrunSdkName => "appletvos"; + #region IPlatformBff implementation public override string BffPlatformDefine => "_TVOS"; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/watchOsPlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/watchOsPlatform.cs index cdf2d2b70..1afcd0627 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/watchOsPlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/watchOsPlatform.cs @@ -25,6 +25,8 @@ public sealed partial class watchOsPlatform : BaseApplePlatform public override string SimplePlatformString => "watchOS"; #endregion + protected override string XcrunSdkName => "watchos"; + #region IPlatformBff implementation public override string BffPlatformDefine => "_WATCHOS"; diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs index bfdae1308..b5dfc78de 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.cs @@ -138,6 +138,7 @@ public virtual void AddCompilerSettings(IDictionary ma public virtual bool ExcludesPrecompiledHeadersFromBuild => false; public virtual bool HasUserAccountControlSupport => false; public virtual bool HasEditAndContinueDebuggingSupport => false; + public virtual bool IsMSVC => true; public virtual void SetupDeleteExtensionsOnCleanOptions(IGenerationContext context) { From d9bda77d33478096cca669e1efee4ac775b378c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 10:40:06 +0000 Subject: [PATCH 3/6] Add NMakePreprocessorDefinitions, NMakeForcedIncludes, AdditionalOptions to Apple platform vcxproj General2 template Co-authored-by: van800 <1482681+van800@users.noreply.github.com> --- .../Apple/BaseApplePlatform.cs | 93 ++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs index 1ae788c04..71790fce2 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs @@ -575,6 +575,74 @@ public void SetupStaticLibraryPaths(Project.Configuration configuration, Depende private static readonly Dictionary> s_clangSystemIncludeCache = new Dictionary>(); private static readonly object s_clangSystemIncludeCacheLock = new object(); + private static readonly Dictionary> s_clangBuiltinDefinesCache = new Dictionary>(); + private static readonly object s_clangBuiltinDefinesCacheLock = new object(); + + // Returns "NAME=VALUE" strings for all non-function-like built-in macros reported by + // clang++ -dM -E -x c++ /dev/null [-std=] -isysroot + private static IReadOnlyList GetClangBuiltinDefinesForSdk(string sdkName, string stdFlag = null) + { + string cacheKey = string.IsNullOrEmpty(stdFlag) ? sdkName : $"{sdkName}|{stdFlag}"; + lock (s_clangBuiltinDefinesCacheLock) + { + if (s_clangBuiltinDefinesCache.TryGetValue(cacheKey, out var cached)) + return cached; + + var result = new List(); + try + { + string sdkPath = RunProcessAndGetOutput("xcrun", $"--sdk {sdkName} --show-sdk-path").Trim(); + if (!string.IsNullOrEmpty(sdkPath)) + { + string stdArg = string.IsNullOrEmpty(stdFlag) ? string.Empty : $"{stdFlag} "; + string clangOutput = RunProcessAndGetOutput( + "clang++", + $"-dM -E -x c++ /dev/null {stdArg}-isysroot \"{sdkPath}\"" + ); + + foreach (string line in clangOutput.Split('\n')) + { + string trimmed = line.Trim(); + if (!trimmed.StartsWith("#define ", StringComparison.Ordinal)) + continue; + + string rest = trimmed.Substring(8).Trim(); + int space = rest.IndexOf(' '); + string name, value; + if (space < 0) + { + name = rest; + value = "1"; + } + else + { + name = rest.Substring(0, space); + value = rest.Substring(space + 1).Trim(); + if (value.Length == 0) + value = "1"; + } + + // Skip function-like macros: NAME( + if (name.IndexOf('(') >= 0) + continue; + + // Normalize whitespace in value + value = System.Text.RegularExpressions.Regex.Replace(value, @"\s+", " "); + result.Add($"{name}={value}"); + } + } + } + catch (Exception ex) + { + Trace.TraceWarning($"[Sharpmake] Could not discover built-in defines for SDK '{sdkName}': {ex.Message}"); + } + + IReadOnlyList readOnly = result.AsReadOnly(); + s_clangBuiltinDefinesCache[cacheKey] = readOnly; + return readOnly; + } + } + private static IReadOnlyList GetClangSystemIncludePathsForSdk(string sdkName) { lock (s_clangSystemIncludeCacheLock) @@ -1565,7 +1633,27 @@ public void SelectBuildType(IGenerationContext context) public virtual void SelectPreprocessorDefinitionsVcxproj(IVcxprojGenerationContext context) { - // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + var defines = new Strings(); + defines.AddRange(context.Options.ExplicitDefines); + defines.AddRange(context.Configuration.Defines); + + // Extract -DFOO defines from AdditionalCompilerOptions + foreach (string compilerOption in context.Configuration.AdditionalCompilerOptions) + { + if (compilerOption.StartsWith("-D", StringComparison.Ordinal)) + defines.Add(compilerOption.Substring(2)); + } + + // Determine the C++ language standard flag (e.g. "-std=c++17") to pass to clang++ + // so that built-in defines like __cplusplus reflect the correct value. + context.CommandLineOptions.TryGetValue("CppLanguageStd", out string cppStdFlag); + if (string.IsNullOrEmpty(cppStdFlag) || cppStdFlag == FileGeneratorUtilities.RemoveLineTag) + cppStdFlag = null; + + // Add built-in compiler defines (clang++ -dM -E [-std=] -x c++ /dev/null) for IntelliSense + defines.AddRange(GetClangBuiltinDefinesForSdk(XcrunSdkName, cppStdFlag)); + + context.Options["PreprocessorDefinitions"] = defines.JoinStrings(";"); } public bool HasPrecomp(IGenerationContext context) @@ -1635,7 +1723,10 @@ public void GenerateProjectConfigurationGeneral(IVcxprojGenerationContext contex private const string _projectConfigurationsGeneral2 = @" + [EscapeXML:options.PreprocessorDefinitions][EscapeXML:options.IntellisenseAdditionalDefines] [options.NMakeIncludeSearchPath] + [options.ForcedIncludeFiles] + [options.IntellisenseCommandLineOptions] "; From 3ded4c0973d5835b9247146cdf55793c6658b099 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 20:39:28 +0000 Subject: [PATCH 4/6] Add MSBuild Build/Rebuild/Clean Target elements to vcxproj when not MSVC --- .../VisualStudio/Vcxproj.Template.cs | 12 ++++++++++++ Sharpmake.Generators/VisualStudio/Vcxproj.cs | 3 +++ .../Apple/BaseApplePlatform.cs | 10 +++++++++- .../HelloXCode.CommonProject.sharpmake.cs | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs index 7714923e5..266c301c1 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs @@ -188,6 +188,18 @@ public static class Project @" "; + public static string NMakeBuildTargets = +@" + + + + + + + + +"; + public static string ProjectConfigurationsResourceCompile = @" [options.ResourceCompileTag] [options.ResourcePreprocessorDefinitions];%(PreprocessorDefinitions) diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index ba7c91fe7..9d4a81897 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -764,6 +764,9 @@ private void GenerateImpl(GenerationContext context, IList generatedFile platform.GenerateRunFromPcDeployment(context, fileGenerator); } + if (!isMSVC) + fileGenerator.Write(Template.Project.NMakeBuildTargets); + fileGenerator.Write(Template.Project.ProjectEnd); // remove all line that contain RemoveLineTag diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs index 71790fce2..1ca22bc9b 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs @@ -1730,6 +1730,14 @@ public void GenerateProjectConfigurationGeneral(IVcxprojGenerationContext contex "; + private const string _projectConfigurationsCustomMakefile = + @" + [conf.CustomBuildSettings.BuildCommand] + [conf.CustomBuildSettings.RebuildCommand] + [conf.CustomBuildSettings.CleanCommand] + +"; + public void GenerateProjectConfigurationGeneral2(IVcxprojGenerationContext context, IFileGenerator generator) { generator.Write(_projectConfigurationsGeneral2); @@ -1742,7 +1750,7 @@ public void GenerateProjectConfigurationFastBuildMakeFile(IVcxprojGenerationCont public void GenerateProjectConfigurationCustomMakeFile(IVcxprojGenerationContext context, IFileGenerator generator) { - // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + generator.Write(_projectConfigurationsCustomMakefile); } public void GenerateProjectPlatformImportSheet(IVcxprojGenerationContext context, IFileGenerator generator) diff --git a/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs b/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs index 4b9ef0ac5..b6badb8c9 100644 --- a/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs +++ b/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs @@ -71,6 +71,21 @@ public virtual void ConfigureAll(Configuration conf, CommonTarget target) } else conf.Options.Add(Sharpmake.Options.XCode.Compiler.DebugInformationFormat.Dwarf); + + if (target.DevEnv != DevEnv.xcode && target.BuildSystem != BuildSystem.FastBuild) + { + // Provide NMake build/rebuild/clean commands so MSBuild can invoke xcodebuild + // for this project when opened via the generated vcxproj. + string xcodeProjectName = $"{Name}_{target.Platform}"; + string xcodeProjectPath = Path.Combine(Globals.TmpDirectory, "projects", Name, xcodeProjectName + ".xcodeproj"); + string xcodeConfiguration = target.Optimization.ToString(); // "Debug" or "Release" + conf.CustomBuildSettings = new Configuration.NMakeBuildSettings + { + BuildCommand = $"xcodebuild build -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration}", + RebuildCommand = $"xcodebuild clean build -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration}", + CleanCommand = $"xcodebuild clean -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration}", + }; + } } //////////////////////////////////////////////////////////////////////// From ca9b40626e1a34293df8bb7cb1480d46b1804d56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 21:57:00 +0000 Subject: [PATCH 5/6] Add FastBuild NMake template to BaseApplePlatform; fix xcodeproj path; add IntelliSense props to CustomMakefile Co-authored-by: van800 <1482681+van800@users.noreply.github.com> --- .../Apple/BaseApplePlatform.cs | 21 ++++++++++- .../HelloXCode.CommonProject.sharpmake.cs | 18 ++++++--- .../static_prelinked_lib1.sharpmake.cs | 37 ++++++++++++------- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs index 1ca22bc9b..9cbd1e3fc 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Apple/BaseApplePlatform.cs @@ -1730,11 +1730,30 @@ public void GenerateProjectConfigurationGeneral(IVcxprojGenerationContext contex "; + private const string _projectConfigurationsFastBuildMakefile = + @" + cd [fastBuildWorkingDirectory] +[conf.FastBuildCustomActionsBeforeBuildCommand] +[fastBuildMakeCommandBuild] + cd [fastBuildWorkingDirectory] +[conf.FastBuildCustomActionsBeforeBuildCommand] +[fastBuildMakeCommandRebuild] + [EscapeXML:options.PreprocessorDefinitions][EscapeXML:options.IntellisenseAdditionalDefines] + [options.NMakeIncludeSearchPath] + [options.ForcedIncludeFiles] + [options.IntellisenseCommandLineOptions] + +"; + private const string _projectConfigurationsCustomMakefile = @" [conf.CustomBuildSettings.BuildCommand] [conf.CustomBuildSettings.RebuildCommand] [conf.CustomBuildSettings.CleanCommand] + [EscapeXML:options.PreprocessorDefinitions][EscapeXML:options.IntellisenseAdditionalDefines] + [options.NMakeIncludeSearchPath] + [options.ForcedIncludeFiles] + [options.IntellisenseCommandLineOptions] "; @@ -1745,7 +1764,7 @@ public void GenerateProjectConfigurationGeneral2(IVcxprojGenerationContext conte public void GenerateProjectConfigurationFastBuildMakeFile(IVcxprojGenerationContext context, IFileGenerator generator) { - // throw new NotImplementedException(SimplePlatformString + " should not be called by a Vcxproj generator"); + generator.Write(_projectConfigurationsFastBuildMakefile); } public void GenerateProjectConfigurationCustomMakeFile(IVcxprojGenerationContext context, IFileGenerator generator) diff --git a/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs b/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs index b6badb8c9..66640f7d5 100644 --- a/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs +++ b/samples/HelloXCode/HelloXCode.CommonProject.sharpmake.cs @@ -76,14 +76,20 @@ public virtual void ConfigureAll(Configuration conf, CommonTarget target) { // Provide NMake build/rebuild/clean commands so MSBuild can invoke xcodebuild // for this project when opened via the generated vcxproj. - string xcodeProjectName = $"{Name}_{target.Platform}"; - string xcodeProjectPath = Path.Combine(Globals.TmpDirectory, "projects", Name, xcodeProjectName + ".xcodeproj"); - string xcodeConfiguration = target.Optimization.ToString(); // "Debug" or "Release" + // The xcodeproj is generated in the same directory as the vcxproj, so we use + // $(MSBuildProjectDirectory) to resolve the correct path at build time. + string xcodeProjectName = $"{Name}_{Util.GetSimplePlatformString(target.Platform)}"; + string xcodeProjectPath = $"$(MSBuildProjectDirectory)/{xcodeProjectName}.xcodeproj"; + // XCode configurations are named after target.Name which uses ToLowerInvariant() + // (e.g. "debug", "release"), so we must match that casing here. + // ONLY_ACTIVE_ARCH=NO ensures all architectures are built so that + // dependent projects (e.g. pre-linked libs) are consistent across archs. + string xcodeConfiguration = target.Optimization.ToString().ToLowerInvariant(); conf.CustomBuildSettings = new Configuration.NMakeBuildSettings { - BuildCommand = $"xcodebuild build -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration}", - RebuildCommand = $"xcodebuild clean build -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration}", - CleanCommand = $"xcodebuild clean -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration}", + BuildCommand = $"xcodebuild build -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration} ONLY_ACTIVE_ARCH=NO", + RebuildCommand = $"xcodebuild clean build -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration} ONLY_ACTIVE_ARCH=NO", + CleanCommand = $"xcodebuild clean -project \"{xcodeProjectPath}\" -configuration {xcodeConfiguration} ONLY_ACTIVE_ARCH=NO", }; } } diff --git a/samples/HelloXCode/codebase/static_prelinked_lib_consumer/static_prelinked_lib1.sharpmake.cs b/samples/HelloXCode/codebase/static_prelinked_lib_consumer/static_prelinked_lib1.sharpmake.cs index e50267ae8..37877c113 100644 --- a/samples/HelloXCode/codebase/static_prelinked_lib_consumer/static_prelinked_lib1.sharpmake.cs +++ b/samples/HelloXCode/codebase/static_prelinked_lib_consumer/static_prelinked_lib1.sharpmake.cs @@ -30,20 +30,29 @@ public override void ConfigureAll(Configuration conf, CommonTarget target) conf.IncludePaths.Add(SourceRootPath); - // Important! do not link the Consumed library - let it be pre-linked by XCode - conf.AddPrivateDependency(target, DependencySetting.DefaultWithoutLinking); - - // Custom build step - to generate the sub library - var platform = Util.GetSimplePlatformString(target.GetPlatform()); - var projPath = Path.Combine(Globals.TmpDirectory, "projects/static_prelinked_lib_consumed"); - var configuration = target.Optimization.ToString().ToLowerInvariant(); - conf.EventPreBuild.Add($"xcodebuild build -scheme static_prelinked_lib_consumed_{platform} -project {projPath}/static_prelinked_lib_consumed_{platform}.xcodeproj -configuration {configuration}"); - - // Test pre-linked libraries - var libraryToPrelink = Path.Combine(conf.TargetLibraryPath, "..", "static_prelinked_lib_consumed", "libstatic_prelinked_lib_consumed.a"); - - conf.Options.Add(Options.XCode.Linker.PerformSingleObjectPrelink.Enable); - conf.Options.Add(new Options.XCode.Linker.PrelinkLibraries(libraryToPrelink)); + if (target.BuildSystem == BuildSystem.FastBuild) + { + // FastBuild does not support XCode pre-linking options, so link the consumed + // library normally so all symbols are available at link time. + conf.AddPrivateDependency(target); + } + else + { + // Important! do not link the Consumed library - let it be pre-linked by XCode + conf.AddPrivateDependency(target, DependencySetting.DefaultWithoutLinking); + + // Custom build step - to generate the sub library + var platform = Util.GetSimplePlatformString(target.GetPlatform()); + var projPath = Path.Combine(Globals.TmpDirectory, "projects/static_prelinked_lib_consumed"); + var configuration = target.Optimization.ToString().ToLowerInvariant(); + conf.EventPreBuild.Add($"xcodebuild build ONLY_ACTIVE_ARCH=NO -scheme static_prelinked_lib_consumed_{platform} -project {projPath}/static_prelinked_lib_consumed_{platform}.xcodeproj -configuration {configuration}"); + + // Test pre-linked libraries + var libraryToPrelink = Path.Combine(conf.TargetLibraryPath, "..", "static_prelinked_lib_consumed", "libstatic_prelinked_lib_consumed.a"); + + conf.Options.Add(Options.XCode.Linker.PerformSingleObjectPrelink.Enable); + conf.Options.Add(new Options.XCode.Linker.PrelinkLibraries(libraryToPrelink)); + } } } } From c86aaeea9e1dc6b0bd7ebd3ec8bfee4b1c1a0c0b Mon Sep 17 00:00:00 2001 From: Ivan Shakhov Date: Sat, 4 Apr 2026 18:47:11 +0200 Subject: [PATCH 6/6] handle non-MSVC excluded files using `` instead of `` --- .../VisualStudio/Vcxproj.Template.cs | 3 +++ Sharpmake.Generators/VisualStudio/Vcxproj.cs | 25 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs index 266c301c1..1f20ea157 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.Template.cs @@ -385,6 +385,9 @@ public static class Project public static string ProjectFilesSourceExcludeFromBuild = @" true +"; + public static string ProjectFilesSourceRemoveFromBuild = + @" "; public static string ProjectFilesSourceConsumeWinRTExtensions = @" true diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index 9d4a81897..698c76a97 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -1605,6 +1605,9 @@ IList skipFiles foreach (Project.Configuration conf in context.ProjectConfigurations) configurationCompiledFiles.Add(new List()); + // Collects files excluded from build on non-MSVC platforms; written as after the ItemGroup + var nonMSVCExcludedFiles = new List<(ProjectFile File, Project.Configuration Conf)>(); + bool hasCustomBuildForAllSources = context.ProjectConfigurations.First().CustomBuildForAllSources != null; if (hasCustomBuildForAllSources) { @@ -1689,6 +1692,9 @@ IList skipFiles if (!isExcludeFromBuild && !isResource) compiledFiles.Add(file); + if (isExcludeFromBuild && !platformVcxproj.IsMSVC && !isResource) + nonMSVCExcludedFiles.Add((file, conf)); + if (isCompileAsCLRFile || consumeWinRTExtensions || excludeWinRTExtensions) isDontUsePrecomp = true; if (string.Compare(file.FileExtension, ".c", StringComparison.OrdinalIgnoreCase) == 0) @@ -1711,7 +1717,7 @@ IList skipFiles bool hasExceptionSetting = !string.IsNullOrEmpty(exceptionSetting); haveFileOptions = haveFileOptions || - isExcludeFromBuild || + (isExcludeFromBuild && platformVcxproj.IsMSVC) || isPrecompSource || (isDontUsePrecomp && hasPrecomp) || hasForcedIncludes || @@ -1750,7 +1756,8 @@ IList skipFiles if (isExcludeFromBuild) { - fileGenerator.Write(Template.Project.ProjectFilesSourceExcludeFromBuild); + if (platformVcxproj.IsMSVC) + fileGenerator.Write(Template.Project.ProjectFilesSourceExcludeFromBuild); } else { @@ -2012,6 +2019,20 @@ IList skipFiles } } } + + // Write entries for files excluded from build on non-MSVC platforms + if (nonMSVCExcludedFiles.Count > 0) + { + foreach (var (excludedFile, excludedConf) in nonMSVCExcludedFiles) + { + using (fileGenerator.Declare("file", excludedFile)) + using (fileGenerator.Declare("conf", excludedConf)) + using (fileGenerator.Declare("platformName", Util.GetToolchainPlatformString(excludedConf.Platform, excludedConf.Project, excludedConf.Target))) + { + fileGenerator.Write(Template.Project.ProjectFilesSourceRemoveFromBuild); + } + } + } // done! fileGenerator.Write(Template.Project.ProjectFilesEnd);