Skip to content

Commit db2d8a0

Browse files
committed
Merge branch 'fix-broken-intellisense-fastbuild-customdefines' into 'main'
Improve support for intellisense in Visual Studio for fastbuild(nmake projects) See merge request Sharpmake/sharpmake!590
2 parents 5356e9b + fbc2fd4 commit db2d8a0

File tree

5 files changed

+104
-45
lines changed

5 files changed

+104
-45
lines changed

Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs

+38-40
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
236236
{
237237
var forcedIncludes = new Strings();
238238

239+
bool useClang = context.Configuration.Platform.IsUsingClang();
239240
bool useClangCl = Options.GetObject<Options.Vc.General.PlatformToolset>(context.Configuration).IsLLVMToolchain() &&
240241
Options.GetObject<Options.Vc.LLVM.UseClangCl>(context.Configuration) == Options.Vc.LLVM.UseClangCl.Enable;
241242

@@ -367,46 +368,6 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
367368
);
368369
}
369370

370-
// MSVC NMake IntelliSence options
371-
372-
context.Options["AdditionalOptions"] = (context.Configuration.CustomBuildSettings is null) ? FileGeneratorUtilities.RemoveLineTag : context.Configuration.CustomBuildSettings.AdditionalOptions;
373-
374-
string cppLanguageStd = null;
375-
if (context.Configuration.CustomBuildSettings is null || context.Configuration.CustomBuildSettings.AutoConfigure)
376-
{
377-
context.SelectOption
378-
(
379-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP98, () => { }),
380-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP11, () => { }),
381-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP14, () => { cppLanguageStd = "/std:c++14"; }),
382-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP17, () => { cppLanguageStd = "/std:c++17"; }),
383-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP20, () => { cppLanguageStd = "/std:c++20"; }),
384-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU98, () => { }),
385-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU11, () => { }),
386-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU14, () => { cppLanguageStd = "/std:c++14"; }),
387-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU17, () => { cppLanguageStd = "/std:c++17"; }),
388-
Options.Option(Options.Vc.Compiler.CppLanguageStandard.Latest, () => { cppLanguageStd = "/std:c++latest"; })
389-
);
390-
}
391-
392-
if (!string.IsNullOrEmpty(cppLanguageStd))
393-
{
394-
if (string.IsNullOrEmpty(context.Options["AdditionalOptions"]) || context.Options["AdditionalOptions"] == FileGeneratorUtilities.RemoveLineTag)
395-
context.Options["AdditionalOptions"] = cppLanguageStd;
396-
else
397-
context.Options["AdditionalOptions"] += $" {cppLanguageStd}";
398-
}
399-
else if (string.IsNullOrEmpty(context.Options["AdditionalOptions"]))
400-
{
401-
context.Options["AdditionalOptions"] = FileGeneratorUtilities.RemoveLineTag;
402-
}
403-
404-
if (useClangCl && context.Options["AdditionalOptions"] != FileGeneratorUtilities.RemoveLineTag)
405-
{
406-
// need to use a special syntax when compiler is clang or Visual Studio will generate intellisense errors
407-
context.Options["AdditionalOptions"] = context.Options["AdditionalOptions"].Replace("/std:c++", "/Clangstdc++");
408-
}
409-
410371
// Compiler section
411372

412373
context.SelectOption
@@ -1208,6 +1169,43 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
12081169
}
12091170

12101171
optionsContext.HasClrSupport = clrSupport;
1172+
1173+
//--------------------------------
1174+
// MSVC NMake IntelliSence options
1175+
//--------------------------------
1176+
1177+
// Handle C++ language version option
1178+
string intellisenseCppLanguageStandard;
1179+
if (!context.CommandLineOptions.TryGetValue("LanguageStandard", out intellisenseCppLanguageStandard) || intellisenseCppLanguageStandard == FileGeneratorUtilities.RemoveLineTag)
1180+
{
1181+
if (!context.CommandLineOptions.TryGetValue("CppLanguageStd", out intellisenseCppLanguageStandard))
1182+
intellisenseCppLanguageStandard = FileGeneratorUtilities.RemoveLineTag;
1183+
}
1184+
1185+
if (intellisenseCppLanguageStandard != FileGeneratorUtilities.RemoveLineTag)
1186+
{
1187+
if (useClangCl || useClang)
1188+
{
1189+
// need to use a special syntax when compiler is clang/clangcl or Visual Studio will generate intellisense errors
1190+
intellisenseCppLanguageStandard = intellisenseCppLanguageStandard.Replace("/std:c++", "/Clangstdc++");
1191+
intellisenseCppLanguageStandard = intellisenseCppLanguageStandard.Replace("-std=c++", "/Clangstdc++");
1192+
}
1193+
}
1194+
1195+
// Merge the intellisense language option with additional intellisense command line options
1196+
string intellisenseCommandLineOptions = intellisenseCppLanguageStandard;
1197+
Strings intellisenseAdditionalCommandlineOptions = context.Configuration.IntellisenseAdditionalCommandLineOptions;
1198+
if (intellisenseAdditionalCommandlineOptions != null)
1199+
{
1200+
if (intellisenseCommandLineOptions != FileGeneratorUtilities.RemoveLineTag)
1201+
intellisenseCommandLineOptions += " ";
1202+
intellisenseCommandLineOptions += string.Join(' ', intellisenseAdditionalCommandlineOptions);
1203+
}
1204+
context.Options["IntellisenseCommandLineOptions"] = intellisenseCommandLineOptions;
1205+
1206+
// Add additional defines for intellisense to the default ones set for that target.
1207+
Strings intellisenseDefines = context.Configuration.IntellisenseAdditionalDefines;
1208+
context.Options["IntellisenseAdditionalDefines"] = intellisenseDefines != null ? ";" + String.Join(';', intellisenseDefines) : "";
12111209
}
12121210

12131211
public static List<KeyValuePair<string, string>> ConvertPostBuildCopiesToRelative(Project.Configuration conf, string relativeTo)

Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.Vcxproj.Template.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,10 @@ public abstract partial class BasePlatform
271271
del ""[options.OutputDirectory]\[conf.TargetFileFullName].lib"" &gt;NUL 2&gt;NUL
272272
del ""[options.OutputDirectory]\[conf.TargetFileFullName].pdb"" &gt;NUL 2&gt;NUL</NMakeCleanCommandLine>
273273
<NMakeOutput>[options.OutputFile]</NMakeOutput>
274-
<NMakePreprocessorDefinitions>[EscapeXML:options.PreprocessorDefinitions]</NMakePreprocessorDefinitions>
274+
<NMakePreprocessorDefinitions>[EscapeXML:options.PreprocessorDefinitions][EscapeXML:options.IntellisenseAdditionalDefines]</NMakePreprocessorDefinitions>
275275
<NMakeIncludeSearchPath>[options.AdditionalIncludeDirectories]</NMakeIncludeSearchPath>
276276
<NMakeForcedIncludes>[options.ForcedIncludeFiles]</NMakeForcedIncludes>
277-
<AdditionalOptions>[options.AdditionalOptions]</AdditionalOptions>
277+
<AdditionalOptions>[options.IntellisenseCommandLineOptions]</AdditionalOptions>
278278
</PropertyGroup>
279279
<ItemDefinitionGroup Condition=""'$(Configuration)|$(Platform)'=='[conf.Name]|[platformName]'"">
280280
<NMakeCompile>

Sharpmake/Project.Configuration.cs

+50-3
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,37 @@ public enum FastBuildClangMscVersionDetectionType
16811681
/// </summary>
16821682
public FastBuildClangMscVersionDetectionType FastBuildClangMscVersionDetectionInfo = FastBuildClangMscVersionDetectionType.FullVersion;
16831683

1684+
private Strings _intellisenseAdditionalDefines;
1685+
1686+
/// <summary>
1687+
/// This property is used to have a list of defines that are not used in the build
1688+
/// but are used for intellisense in Visual Studio.
1689+
/// This is only used for fastbuild project(implemented using nmake project)
1690+
/// </summary>
1691+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
1692+
public Strings IntellisenseAdditionalDefines
1693+
{
1694+
get
1695+
{
1696+
return GetDynamicPropertyField(ref _intellisenseAdditionalDefines, () => new Strings());
1697+
}
1698+
}
1699+
1700+
private Strings _intellisenseAdditionalCommandLineOptions;
1701+
/// <summary>
1702+
/// This property is used to have a list of additional command line options that are not used in the build
1703+
/// but are used for intellisense in Visual Studio.
1704+
/// This is only used for fastbuild project(implemented using nmake project)
1705+
/// </summary>
1706+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
1707+
public Strings IntellisenseAdditionalCommandLineOptions
1708+
{
1709+
get
1710+
{
1711+
return GetDynamicPropertyField(ref _intellisenseAdditionalCommandLineOptions, () => new Strings());
1712+
}
1713+
}
1714+
16841715
/// <summary>
16851716
/// Gets or sets whether to generate a FASTBuild (.bff) file when using FASTBuild.
16861717
/// </summary>
@@ -2792,12 +2823,28 @@ internal override void Construct(object owner, ITarget target)
27922823
Output = OutputType.None;
27932824
}
27942825

2795-
private bool _isResolved = false;
2826+
private Resolver.ResolveStates _resolveState = Resolver.ResolveStates.NotResolved;
2827+
2828+
/// <summary>
2829+
/// This helper function is used to implement properties that can only be allocated before resolving takes place. This will
2830+
/// be useful to reduce the number of allocations as we can now have a bunch of null container fields for unused properties.
2831+
/// </summary>
2832+
/// <typeparam name="T"></typeparam>
2833+
/// <param name="propertyField">The internal property field associated with the property</param>
2834+
/// <param name="creator">Simple functor used to allocate the field when the field is accessed(only when we are in configure phase, before resolve)</param>
2835+
/// <returns>T: The backing field or null</returns>
2836+
private T GetDynamicPropertyField<T>(ref T propertyField, Func<T> creator)
2837+
{
2838+
if (propertyField == null && _resolveState == Resolver.ResolveStates.NotResolved)
2839+
propertyField = creator();
2840+
return propertyField;
2841+
}
27962842

27972843
internal void Resolve(Resolver resolver)
27982844
{
2799-
if (_isResolved)
2845+
if (_resolveState != Resolver.ResolveStates.NotResolved)
28002846
throw new Error("Can't resolve twice!");
2847+
_resolveState = Resolver.ResolveStates.InProgress;
28012848

28022849
if (PrecompHeader == null && PrecompSource != null)
28032850
throw new Error("Incoherent settings for {0} : PrecompHeader is null but PrecompSource is not", ToString());
@@ -2979,7 +3026,7 @@ internal void Resolve(Resolver resolver)
29793026
resolver.RemoveParameter("conf");
29803027
resolver.RemoveParameter("target");
29813028

2982-
_isResolved = true;
3029+
_resolveState = Resolver.ResolveStates.Resolved;
29833030
}
29843031

29853032
private void SetDependency(

Sharpmake/Resolver.cs

+11
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ namespace Sharpmake
9393
/// </summary>
9494
public class Resolver
9595
{
96+
/// <summary>
97+
/// This enumeration can be used to implement conditions or validations based on the resolve state.
98+
/// </summary>
99+
public enum ResolveStates
100+
{
101+
NotResolved, // The object is not resolved
102+
InProgress, // The object is currently being resolved
103+
Resolved // The object has been resolved.
104+
};
105+
106+
96107
private class TypeWrapper
97108
{
98109
public List<MemberInfo> MemberInfos;

samples/FastBuildSimpleExecutable/FastBuildSimpleExecutable.sharpmake.cs

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public void ConfigureFastBuild(Configuration conf, Target target)
5050

5151
// Force writing to pdb from different cl.exe process to go through the pdb server
5252
conf.AdditionalCompilerOptions.Add("/FS");
53+
54+
conf.IntellisenseAdditionalDefines.Add("MY_INTELLISENSE_DEFINE", "MY_INTELLISENSE_DEFINE2");
55+
conf.IntellisenseAdditionalCommandLineOptions.Add("/MY_INTELLISENSE_OPTION", "/MY_INTELLISENSE_OPTION2"); // Dummy options just to validate the output
5356
}
5457

5558
[Configure(Optimization.Release)]

0 commit comments

Comments
 (0)