Skip to content

Commit

Permalink
Merge branch 'fix-broken-intellisense-fastbuild-customdefines' into '…
Browse files Browse the repository at this point in the history
…main'

Improve support for intellisense in Visual Studio for fastbuild(nmake projects)

See merge request Sharpmake/sharpmake!590
  • Loading branch information
jspelletier committed Dec 16, 2024
2 parents 5356e9b + fbc2fd4 commit db2d8a0
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 45 deletions.
78 changes: 38 additions & 40 deletions Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
{
var forcedIncludes = new Strings();

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

Expand Down Expand Up @@ -367,46 +368,6 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
);
}

// MSVC NMake IntelliSence options

context.Options["AdditionalOptions"] = (context.Configuration.CustomBuildSettings is null) ? FileGeneratorUtilities.RemoveLineTag : context.Configuration.CustomBuildSettings.AdditionalOptions;

string cppLanguageStd = null;
if (context.Configuration.CustomBuildSettings is null || context.Configuration.CustomBuildSettings.AutoConfigure)
{
context.SelectOption
(
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP98, () => { }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP11, () => { }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP14, () => { cppLanguageStd = "/std:c++14"; }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP17, () => { cppLanguageStd = "/std:c++17"; }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP20, () => { cppLanguageStd = "/std:c++20"; }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU98, () => { }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU11, () => { }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU14, () => { cppLanguageStd = "/std:c++14"; }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU17, () => { cppLanguageStd = "/std:c++17"; }),
Options.Option(Options.Vc.Compiler.CppLanguageStandard.Latest, () => { cppLanguageStd = "/std:c++latest"; })
);
}

if (!string.IsNullOrEmpty(cppLanguageStd))
{
if (string.IsNullOrEmpty(context.Options["AdditionalOptions"]) || context.Options["AdditionalOptions"] == FileGeneratorUtilities.RemoveLineTag)
context.Options["AdditionalOptions"] = cppLanguageStd;
else
context.Options["AdditionalOptions"] += $" {cppLanguageStd}";
}
else if (string.IsNullOrEmpty(context.Options["AdditionalOptions"]))
{
context.Options["AdditionalOptions"] = FileGeneratorUtilities.RemoveLineTag;
}

if (useClangCl && context.Options["AdditionalOptions"] != FileGeneratorUtilities.RemoveLineTag)
{
// need to use a special syntax when compiler is clang or Visual Studio will generate intellisense errors
context.Options["AdditionalOptions"] = context.Options["AdditionalOptions"].Replace("/std:c++", "/Clangstdc++");
}

// Compiler section

context.SelectOption
Expand Down Expand Up @@ -1208,6 +1169,43 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG
}

optionsContext.HasClrSupport = clrSupport;

//--------------------------------
// MSVC NMake IntelliSence options
//--------------------------------

// Handle C++ language version option
string intellisenseCppLanguageStandard;
if (!context.CommandLineOptions.TryGetValue("LanguageStandard", out intellisenseCppLanguageStandard) || intellisenseCppLanguageStandard == FileGeneratorUtilities.RemoveLineTag)
{
if (!context.CommandLineOptions.TryGetValue("CppLanguageStd", out intellisenseCppLanguageStandard))
intellisenseCppLanguageStandard = FileGeneratorUtilities.RemoveLineTag;
}

if (intellisenseCppLanguageStandard != FileGeneratorUtilities.RemoveLineTag)
{
if (useClangCl || useClang)
{
// need to use a special syntax when compiler is clang/clangcl or Visual Studio will generate intellisense errors
intellisenseCppLanguageStandard = intellisenseCppLanguageStandard.Replace("/std:c++", "/Clangstdc++");
intellisenseCppLanguageStandard = intellisenseCppLanguageStandard.Replace("-std=c++", "/Clangstdc++");
}
}

// Merge the intellisense language option with additional intellisense command line options
string intellisenseCommandLineOptions = intellisenseCppLanguageStandard;
Strings intellisenseAdditionalCommandlineOptions = context.Configuration.IntellisenseAdditionalCommandLineOptions;
if (intellisenseAdditionalCommandlineOptions != null)
{
if (intellisenseCommandLineOptions != FileGeneratorUtilities.RemoveLineTag)
intellisenseCommandLineOptions += " ";
intellisenseCommandLineOptions += string.Join(' ', intellisenseAdditionalCommandlineOptions);
}
context.Options["IntellisenseCommandLineOptions"] = intellisenseCommandLineOptions;

// Add additional defines for intellisense to the default ones set for that target.
Strings intellisenseDefines = context.Configuration.IntellisenseAdditionalDefines;
context.Options["IntellisenseAdditionalDefines"] = intellisenseDefines != null ? ";" + String.Join(';', intellisenseDefines) : "";
}

public static List<KeyValuePair<string, string>> ConvertPostBuildCopiesToRelative(Project.Configuration conf, string relativeTo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,10 @@ public abstract partial class BasePlatform
del ""[options.OutputDirectory]\[conf.TargetFileFullName].lib"" &gt;NUL 2&gt;NUL
del ""[options.OutputDirectory]\[conf.TargetFileFullName].pdb"" &gt;NUL 2&gt;NUL</NMakeCleanCommandLine>
<NMakeOutput>[options.OutputFile]</NMakeOutput>
<NMakePreprocessorDefinitions>[EscapeXML:options.PreprocessorDefinitions]</NMakePreprocessorDefinitions>
<NMakePreprocessorDefinitions>[EscapeXML:options.PreprocessorDefinitions][EscapeXML:options.IntellisenseAdditionalDefines]</NMakePreprocessorDefinitions>
<NMakeIncludeSearchPath>[options.AdditionalIncludeDirectories]</NMakeIncludeSearchPath>
<NMakeForcedIncludes>[options.ForcedIncludeFiles]</NMakeForcedIncludes>
<AdditionalOptions>[options.AdditionalOptions]</AdditionalOptions>
<AdditionalOptions>[options.IntellisenseCommandLineOptions]</AdditionalOptions>
</PropertyGroup>
<ItemDefinitionGroup Condition=""'$(Configuration)|$(Platform)'=='[conf.Name]|[platformName]'"">
<NMakeCompile>
Expand Down
53 changes: 50 additions & 3 deletions Sharpmake/Project.Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,37 @@ public enum FastBuildClangMscVersionDetectionType
/// </summary>
public FastBuildClangMscVersionDetectionType FastBuildClangMscVersionDetectionInfo = FastBuildClangMscVersionDetectionType.FullVersion;

private Strings _intellisenseAdditionalDefines;

/// <summary>
/// This property is used to have a list of defines that are not used in the build
/// but are used for intellisense in Visual Studio.
/// This is only used for fastbuild project(implemented using nmake project)
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Strings IntellisenseAdditionalDefines
{
get
{
return GetDynamicPropertyField(ref _intellisenseAdditionalDefines, () => new Strings());
}
}

private Strings _intellisenseAdditionalCommandLineOptions;
/// <summary>
/// This property is used to have a list of additional command line options that are not used in the build
/// but are used for intellisense in Visual Studio.
/// This is only used for fastbuild project(implemented using nmake project)
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Strings IntellisenseAdditionalCommandLineOptions
{
get
{
return GetDynamicPropertyField(ref _intellisenseAdditionalCommandLineOptions, () => new Strings());
}
}

/// <summary>
/// Gets or sets whether to generate a FASTBuild (.bff) file when using FASTBuild.
/// </summary>
Expand Down Expand Up @@ -2792,12 +2823,28 @@ internal override void Construct(object owner, ITarget target)
Output = OutputType.None;
}

private bool _isResolved = false;
private Resolver.ResolveStates _resolveState = Resolver.ResolveStates.NotResolved;

/// <summary>
/// This helper function is used to implement properties that can only be allocated before resolving takes place. This will
/// be useful to reduce the number of allocations as we can now have a bunch of null container fields for unused properties.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="propertyField">The internal property field associated with the property</param>
/// <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>
/// <returns>T: The backing field or null</returns>
private T GetDynamicPropertyField<T>(ref T propertyField, Func<T> creator)
{
if (propertyField == null && _resolveState == Resolver.ResolveStates.NotResolved)
propertyField = creator();
return propertyField;
}

internal void Resolve(Resolver resolver)
{
if (_isResolved)
if (_resolveState != Resolver.ResolveStates.NotResolved)
throw new Error("Can't resolve twice!");
_resolveState = Resolver.ResolveStates.InProgress;

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

_isResolved = true;
_resolveState = Resolver.ResolveStates.Resolved;
}

private void SetDependency(
Expand Down
11 changes: 11 additions & 0 deletions Sharpmake/Resolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ namespace Sharpmake
/// </summary>
public class Resolver
{
/// <summary>
/// This enumeration can be used to implement conditions or validations based on the resolve state.
/// </summary>
public enum ResolveStates
{
NotResolved, // The object is not resolved
InProgress, // The object is currently being resolved
Resolved // The object has been resolved.
};


private class TypeWrapper
{
public List<MemberInfo> MemberInfos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public void ConfigureFastBuild(Configuration conf, Target target)

// Force writing to pdb from different cl.exe process to go through the pdb server
conf.AdditionalCompilerOptions.Add("/FS");

conf.IntellisenseAdditionalDefines.Add("MY_INTELLISENSE_DEFINE", "MY_INTELLISENSE_DEFINE2");
conf.IntellisenseAdditionalCommandLineOptions.Add("/MY_INTELLISENSE_OPTION", "/MY_INTELLISENSE_OPTION2"); // Dummy options just to validate the output
}

[Configure(Optimization.Release)]
Expand Down

0 comments on commit db2d8a0

Please sign in to comment.