将LLVM/Clang编译器整合到Visual Studio中

一、集成clang-cl编译器

clang-cl是兼容微软cl的模式,它支持微软cl编译器的绝大多数编译选项,目前还有部分选项不支持。

从官网下载编译好的Windows平台安装包,LLVM 6有提供MSBuild集成工具,后续的版本不再提供,所以我们需要先下载LLVM 6并且在安装后把集成工具复制出来,路径在安装目录下的tools目录中。
可以看看目录下的东西:
将LLVM/Clang编译器整合到Visual Studio中_第1张图片
将LLVM/Clang编译器整合到Visual Studio中_第2张图片
将LLVM/Clang编译器整合到Visual Studio中_第3张图片
可以看到支持VS2010、VS2012、VS2013和VS2014(即VS2015),不支持VS2017和VS2019以及VS2010以前的版本,当然可以仔细研究一下这些配置文件,也可以自己做出相应VS版本的支持。(BTW:VS2017有专门的插件可以使用——LLVM Compiler Toolchain,这个工具目前只支持VS2017)

再从官网下载最新的安装包进行安装,目前最新版本是LLVM8.0.0,安装新包会自动卸载掉老包。

把之前复制出来的tools目录放回到安装目录下,打开所有的props文件,把

$(LLVMInstallDir)\lib\clang\6.0\lib\windows;

中的路径替换成当前安装的路径,比如安装了8.0.0的则为:

$(LLVMInstallDir)lib\clang\8.0.0\lib\windows;

然后在安装目录新建一个msbuild-bin目录,把bin目录中的clang-cl.exe复制到msbuild-bin目录,并改名为cl.exe

最后执行tools/msbuild/install.bat即可。

此时可以在项目属性中看到LLVM的踪影了,下图是VS2015的项目属性截图:
将LLVM/Clang编译器整合到Visual Studio中_第4张图片
试试效果:
将LLVM/Clang编译器整合到Visual Studio中_第5张图片
可以看到clang-cl的输出字样,说明成功了。

这里有一个问题,就是没有编译进度显示,即不知道当前编译的是哪个文件。研究了一下MSBuild,发现输出窗口的编译进度(当前编译的哪个文件)是在MSBuild的Microsoft.Build.CPPTasks.Common.dll中的CL任务调用过程中输出当前编译的文件名的,不是在配置文件中输出的。具体的代码为:

private void ReadUnicodeOutput(object stateInfo)
{
	uint num;
	byte[] lpBuffer = new byte[0x400];
	string str = string.Empty;
	while (NativeMethodsShared.ReadFile(this.unicodePipeReadHandle, lpBuffer, 0x400, out num, NativeMethodsShared.NullIntPtr) && (num != 0))
	{
		string str2 = str + Encoding.Unicode.GetString(lpBuffer, 0, (int)num);
		while (true)
		{
			int length = -1;
			length = str2.IndexOf('\n');
			if (length == -1)
			{
				str = str2;
				break;
			}
			string lineOfText = str2.Substring(0, length);
			str2 = str2.Substring(length + 1);
			if ((lineOfText.Length > 0) && lineOfText.EndsWith("\r", StringComparison.Ordinal))
			{
				lineOfText = lineOfText.Substring(0, lineOfText.Length - 1);
			}
			base.Log.LogMessageFromText(lineOfText, base.StandardOutputImportanceToUse);
		}
	}
	if (!string.IsNullOrEmpty(str))
	{
		base.Log.LogMessageFromText(str, base.StandardOutputImportanceToUse);
	}
	this.unicodeOutputEnded.Set();
}

它是利用了MS的CL编译器在编译时会输出文件名的功能,从管道中读取的。而Clang编译器在编译过程中是不会输出当前正在编译的文件名的,从管道中无法读取,所以不能显示当前编译进度。

为了使其显示编译进度,以VS2015为例,需要做出如下处理:

(一)、编写一个MSBuild任务dll

1.新建一个C#类库工程,取名为VSClang
2.新建一个类ClangCl,写下如下代码:

namespace VSClang
{
	using Microsoft.Build.Framework;
	using System.IO;

	public class ClangCl : Microsoft.Build.CPPTasks.CL
	{
		protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
		{
			foreach (ITaskItem item in base.SourcesCompiled)
			{
				base.Log.LogMessage(MessageImportance.High, Path.GetFileName(item.ItemSpec), new object[0]);
			}
			return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
		}
	}
}

3.编译成功后,将生成的VSClang.dll复制到MSBuild安装目录下与Microsoft.Build.CppTasks.Common.dll同一位置,笔者的在C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140下。

(二)、修改安装前配置(如果已经安装过了,修改后再安装一次即可)

  1. 修改x64以及Win32目录下toolset-vs2014.props以及toolset-vs2014_xp.props,如下图所示:
    将LLVM/Clang编译器整合到Visual Studio中_第6张图片
  • 添加-fdiagnostics-absolute-paths参数是为了让Clang在输出诊断信息是以绝对路径输出源文件,否则在Visual Studio中窗口无法双击诊断信息定位到源文件。
  • 添加
<ObjectFileName>$(IntDir)%(filename).objObjectFileName>

是为了让MSBuild在执行编译任务时一次只编译一个源文件,否则会有多个源文件进入编译任务,输出进度与实际编译进度会不匹配。
2. 修改x64以及Win32目录下toolset-vs2014.targets以及toolset-vs2014_xp.targets,

Project>

结束标志之前添加如下配置:

<UsingTask TaskName="ClangCl"            AssemblyFile="$(VCTargetsPath)\VSClang.dll"/>

<Target Name="ClCompile"
          Condition="'@(ClCompile)' != ''"
          DependsOnTargets="SelectClCompile">

    <PropertyGroup>
      <CLToolArchitecture Condition="'$(CLToolArchitecture)' == ''">$(VCToolArchitecture)CLToolArchitecture>
      <CLDeleteOutputOnExecute Condition="'$(CLDeleteOutputOnExecute)' == ''">trueCLDeleteOutputOnExecute>
    PropertyGroup>

    <ItemGroup>
      <ClNoDependencies Condition="'@(ClNoDependencies)' == '' and '%(ClInclude.NoDependency)' == 'true'" Include="@(ClInclude)"/>
      <ClNoDependencies Condition="'$(NoDependencies)' != ''" Include="$(NoDependencies)" />
    ItemGroup>

    
    <Delete Condition="'%(ClCompile.DebugInformationFormat)' != '' and '%(ClCompile.DebugInformationFormat)' != 'None' and '%(ClCompile.DebugInformationFormat)' != 'OldStyle' and '%(ClCompile.ProgramDataBaseFileName)' != '' and !Exists(%(ClCompile.ProgramDataBaseFileName))"
            Files="%(ClCompile.PrecompiledHeaderOutputFile)" />

    
    
    ClangCl>

    
    
    ClangCl>
    
    <OnError Condition="'$(OnXamlPreCompileErrorTarget)' != ''" ExecuteTargets="$(OnXamlPreCompileErrorTarget)" />
  Target>

(三)、点击install.bat进行安装

经过这些处理,在VS2015下使用LLVM-vs2014平台工具集即可看到编译进度。

二、集成clang编译器

由于clang-cl编译器是期望与微软的cl编译器兼容的,所以在跨平台方面会有问题,所以最好是直接使用clang编译器,这样各个平台的编译效果会最大程度地一致(目前使用Clang在Windows下编译还是有一些问题,需要特殊处理)。

笔者依旧以VS2015为例来说明,由于VS2015本身是支持Clang编译器的,可以在安装的时候进行选择安装Clang编译器,但是由于编译器版本太低,所以不推荐。我们完全可以安装最新的Clang编译器。

虽然我们没有安装VS自带的Clang编译器,但是VS默认还是安装了Clang的MSBuild编译配置,大家可以看看图示目录下是否有Microsoft.Cpp.Clang.props和Microsoft.Cpp.Clang.targets两个文件,如果没有可以在后面复制。
将LLVM/Clang编译器整合到Visual Studio中_第7张图片

(一)、添加toolset

在Platforms下的x64以及Win32下添加工具集,比如笔者在x64下添加一个clang工具集,即在

C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Platforms\x64\PlatformToolsets

目录下新建一个clang目录,并在其中添加Toolset.props和Toolset.targets两个文件,

Toolset.props文件内容如下:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildThisFileDirectory)ImportBefore\*.props" Condition="Exists('$(MSBuildThisFileDirectory)ImportBefore')" />

  <PropertyGroup>
    <ClangTarget>amd64-pc-windows-msvcClangTarget>
  PropertyGroup>

  <PropertyGroup>
    
    <OutDirWasSpecified Condition=" '$(OutDir)'!='' AND '$(OutDirWasSpecified)'=='' ">trueOutDirWasSpecified>
    <OutDirWasSpecified Condition=" '$(OutDir)'=='' AND '$(OutDirWasSpecified)'=='' ">falseOutDirWasSpecified>

    <IntDir Condition="'$(IntDir)'=='' AND '$(IntermediateOutputPath)'!=''">$(IntermediateOutputPath)IntDir>
    <IntDir Condition="'$(IntDir)'=='' AND '$(IntermediateOutputPath)'==''">$(Platform)\$(Configuration)\IntDir>
    <OutDir Condition="'$(OutDir)'=='' AND '$(SolutionDir)' == ''">$(IntDir)OutDir>
    <OutDir Condition="'$(OutDir)'=='' AND '$(SolutionDir)' != ''">$(SolutionDir)$(Platform)\$(Configuration)\OutDir>
  PropertyGroup>

  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.WindowsSDK.props" Condition="Exists('$(VCTargetsPath)\Microsoft.Cpp.WindowsSDK.props')"/>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Common.props" />
  
  
  <PropertyGroup>
    <GNUMode>trueGNUMode>
    <MSVCErrorReport>trueMSVCErrorReport>
    <ToolsetISenseIdentifier>Clang.WindowsToolsetISenseIdentifier>
  PropertyGroup>

  <PropertyGroup>
    <VCClangInstallDir Condition="'$(VCClangInstallDir)' == ''">$(VCInstallDir)ClangC2\VCClangInstallDir>
    <VCClangBinDir Condition="'$(VCToolArchitecture)' == 'Native64Bit'">$(VCClangInstallDir)bin\amd64VCClangBinDir>
    <VCClangBinDir Condition="'$(VCToolArchitecture)' != 'Native64Bit'">$(VCClangInstallDir)bin\x86VCClangBinDir>
  PropertyGroup>

  <ItemDefinitionGroup>
    <ClCompile>
      <MSExtensions>falseMSExtensions>
      <MSCompatibility>falseMSCompatibility>
      <PreprocessorDefinitions Condition="'$(UseDebugLibraries)' != 'true'">NDEBUG;%(PreprocessorDefinitions)PreprocessorDefinitions>
      <AdditionalOptions>-g -gcodeview -fdiagnostics-absolute-paths -fno-delayed-template-parsing -Xclang -flto-visibility-public-std %(AdditionalOptions)AdditionalOptions>
    ClCompile>
  ItemDefinitionGroup>

  <PropertyGroup>
    <ExecutablePath Condition="'$(ExecutablePath)' == ''">$(VCClangBinDir)\amd64;$(VCClangBinDir);$(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH);ExecutablePath>
    <IncludePath Condition="'$(IncludePath)' == ''">$(VCClangInstallDir)include;$(VC_IncludePath);$(WindowsSDK_IncludePath);IncludePath>
    <ReferencePath Condition="'$(ReferencePath)' == ''">$(VC_ReferencesPath_x64);ReferencePath>
    <LibraryPath Condition="'$(LibraryPath)' == ''">$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64LibraryPath>
    <LibraryWPath Condition="'$(LibraryWPath)' == ''">$(WindowsSDK_MetadataPath);LibraryWPath>
    <SourcePath Condition="'$(SourcePath)' == ''">$(VC_SourcePath);SourcePath>
    <ExcludePath Condition="'$(ExcludePath)' == ''">$(VC_IncludePath);$(WindowsSDK_IncludePath);$(MSBuild_ExecutablePath);$(VC_LibraryPath_x64);ExcludePath>
    <DebugCppRuntimeFilesPath Condition="'$(DebugCppRuntimeFilesPath)' == ''">$(VCInstallDir)redist\Debug_NonRedist\x64DebugCppRuntimeFilesPath>	
  PropertyGroup>

  <Import Project="$(MSBuildThisFileDirectory)ImportAfter\*.props" Condition="Exists('$(MSBuildThisFileDirectory)ImportAfter')" />
  
  
  <Import Project="$(_PlatformFolder)Platform.Common.props" />
  
  
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Clang.props" />
  
  
  <ItemDefinitionGroup>
    <ClCompile>
      <MSExtensions>trueMSExtensions>
      <MSCompatibility>trueMSCompatibility>
      <PositionIndependentCode>falsePositionIndependentCode>
      <RuntimeTypeInfo>trueRuntimeTypeInfo>
      <DebugInformationFormat>LineNumberDebugInformationFormat>
	  <WarningLevel>EnableAllWarningsWarningLevel>
	  <UseMultiToolTask>trueUseMultiToolTask>
    ClCompile>
  ItemDefinitionGroup>
Project>

Toolset.targets文件内容如下:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Import Project="$(MSBuildThisFileDirectory)ImportBefore\*.targets" Condition="Exists('$(MSBuildThisFileDirectory)ImportBefore')" />

  <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" />
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Clang.targets" />

  <Import Project="$(MSBuildThisFileDirectory)ImportAfter\*.targets" Condition="Exists('$(MSBuildThisFileDirectory)ImportAfter')" />

Project>

添加了这两个文件后,就可以在VS中看到工具集了:
将LLVM/Clang编译器整合到Visual Studio中_第8张图片
这样就大功告成了。如果没有Microsoft.Cpp.Clang.props与Microsoft.Cpp.Clang.targets两个文件,可以从下面复制出来放在

C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140

目录即可。

VS 2015所带的Microsoft.Cpp.Clang.props完整内容如下:



<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildThisFileDirectory)ImportBefore\*.props" Condition="Exists('$(MSBuildThisFileDirectory)ImportBefore')" />

  <ItemDefinitionGroup>
    <ClCompile>
      <ClangMode>trueClangMode>
      <WarningLevel>EnableAllWarningsWarningLevel>
      <DebugInformationFormat Condition="'$(UseDebugLibraries)' == 'true'">FullDebugDebugInformationFormat>
      <DebugInformationFormat Condition="'$(UseDebugLibraries)' != 'true'">LineNumberDebugInformationFormat>
      <PreprocessorDefinitions Condition="'$(UseDebugLibraries)' == 'true'">NDEBUG;%(PreprocessorDefinitions)PreprocessorDefinitions>
      <Optimization Condition="'$(UseDebugLibraries)' == 'true'">DisabledOptimization>
      <Optimization Condition="'$(UseDebugLibraries)' != 'true'">FullOptimization>
      <StrictAliasing>falseStrictAliasing>
      <ProgramDatabaseFileName>$(IntDir)ProgramDatabaseFileName>
      <OmitFramePointers Condition="'$(UseDebugLibraries)' == 'true'">falseOmitFramePointers>
      <OmitFramePointers Condition="'$(UseDebugLibraries)' != 'true'">trueOmitFramePointers>
      <ExceptionHandling>EnabledExceptionHandling>
      <FunctionLevelLinking Condition="'$(UseDebugLibraries)' == 'true'">falseFunctionLevelLinking>
      <FunctionLevelLinking Condition="'$(UseDebugLibraries)' != 'true'">trueFunctionLevelLinking>
      <DataLevelLinking Condition="'$(UseDebugLibraries)' == 'true'">falseDataLevelLinking>
      <DataLevelLinking Condition="'$(UseDebugLibraries)' != 'true'">trueDataLevelLinking>
      <BufferSecurityCheck>trueBufferSecurityCheck>
      <PositionIndependentCode>truePositionIndependentCode>
      <UseShortEnums>falseUseShortEnums>
      <RuntimeTypeInfo>falseRuntimeTypeInfo>
      <CLanguageStandard>DefaultCLanguageStandard>
      <CppLanguageStandard>DefaultCppLanguageStandard>
      <PrecompiledHeader>NotUsingPrecompiledHeader>
      <ObjectFileName>$(IntDir)%(filename).objObjectFileName>
      <CompileAs>DefaultCompileAs>
      <TreatWarningAsError>falseTreatWarningAsError>
      <Verbose>falseVerbose>
      <EnablePREfast Condition="'%(ClCompile.EnablePREfast)' == ''">falseEnablePREfast>
      <OmitFramePointers Condition="'%(ClCompile.OmitFramePointers)' == ''">falseOmitFramePointers>
      <MinimalRebuildFromTracking>trueMinimalRebuildFromTracking>
      <PrecompiledHeaderOutputFileDirectory>$(IntDir)PrecompiledHeaderOutputFileDirectory>
      <PrecompiledHeaderOutputFile>PrecompiledHeaderOutputFile>
      <PrecompiledHeaderCompileAs>CompileAsCppPrecompiledHeaderCompileAs>
    ClCompile>
  ItemDefinitionGroup>

  <Import Project="$(MSBuildThisFileDirectory)ImportAfter\*.props" Condition="Exists('$(MSBuildThisFileDirectory)ImportAfter')" />
Project>

Microsoft.Cpp.Clang.targets完整内容如下:



<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <UsingTask TaskName="ClangCompile" AssemblyFile="$(VCTargetsPath)Microsoft.Build.CppTasks.Common.dll"/>

  

  <Target Name="FixupCLCompileOptions"
          Condition="'@(ClCompile)' != ''">
    <ItemGroup>
      <ClCompile>
        <PrecompiledHeaderOutputFileDirectory Condition="'%(ClCompile.PrecompiledHeaderOutputFileDirectory)' != '' and !HasTrailingSlash('%(ClCompile.PrecompiledHeaderOutputFileDirectory)')">%(ClCompile.PrecompiledHeaderOutputFileDirectory)\PrecompiledHeaderOutputFileDirectory>
      ClCompile>

    
      <ClCompilePCH Condition="'%(ClCompile.PrecompiledHeaderFile)' != '' and '%(ClCompile.PrecompiledHeader)' == 'Use'" Include="@(ClCompile->Metadata(PrecompiledHeaderFile)->Fullpath()->Distinct()->ClearMetadata())">
        <CompileAs/>
        <ForcedIncludeFiles/>
        <PrecompiledHeaderFile/>
        <PrecompiledHeader>CreatePrecompiledHeader>
        <PrecompiledHeaderCompileAs>%(ClCompile.PrecompiledHeaderCompileAs)PrecompiledHeaderCompileAs>
        <PrecompiledHeaderOutputFileDirectory>%(ClCompile.PrecompiledHeaderOutputFileDirectory)PrecompiledHeaderOutputFileDirectory>
        
        <LibCompiled>falseLibCompiled>
        <LinkCompiled>falseLinkCompiled>
      ClCompilePCH>

      <ClCompilePCH>
        <ObjectFileName>%(ClCompilePCH.PrecompiledHeaderOutputFileDirectory)%(FileName)%(Extension).gchObjectFileName>
      ClCompilePCH>

      
      <ClCompile Condition="'%(ClCompile.PrecompiledHeader)' == 'Use' and '$(DesignTimeBuild)' == 'true'">
        
        
        <ForcedIncludeFiles>%(ClCompile.PrecompiledHeaderFile);%(ClCompile.ForcedIncludeFiles)ForcedIncludeFiles>
        <PrecompiledHeaderOutputFile>%(PrecompiledHeaderOutputFileDirectory)%(ClCompile.PrecompiledHeaderFile).gchPrecompiledHeaderOutputFile>
      ClCompile>

      <ClCompile Condition="'%(ClCompile.PrecompiledHeader)' == 'Use' and '$(DesignTimeBuild)' != 'true' and '%(Identity)' != ''">
        <ForcedIncludeFiles>@(ClCompile->Metadata(PrecompiledHeaderFile)->'%(PrecompiledHeaderOutputFileDirectory)%(FileName)%(Extension)');%(ClCompile.ForcedIncludeFiles)ForcedIncludeFiles>
        
        <MultiToolTaskDependency>@(ClCompile->Metadata(PrecompiledHeaderFile)->Fullpath()->Distinct()->ClearMetadata())MultiToolTaskDependency>
      ClCompile>

      
      <ClCompile>
        <PrecompiledHeaderFile />
        <PrecompiledHeaderCompileAs />
        <PrecompiledHeaderOutputFileDirectory />
      ClCompile>

      <ClCompilePCH>
        <PrecompiledHeaderOutputFileDirectory />
        <RuntimeTypeInfo Condition="'%(ClCompilePCH.PrecompiledHeaderCompileAs)' == 'CompileAsC'" />
      ClCompilePCH>

      <ClCompile Condition="'$(DesignTimeBuild)' != 'true'" Include="@(ClCompilePCH)" />

      <ClCompile>
        <BuildingInIDE>$(BuildingInsideVisualStudio)BuildingInIDE>
        <GNUMode>$(GNUMode)GNUMode>
        <MSVCErrorReport>$(MSVCErrorReport)MSVCErrorReport>
        <GccToolChain>$(GccToolchainPrebuiltPath)GccToolChain>
        <Sysroot>$(Sysroot)Sysroot>
        <TargetArch>$(ClangTarget)TargetArch>
        <MinimalRebuildFromTracking Condition="'$(_BuildActionType)' != 'Build' or '$(ForceRebuild)' == 'true'">falseMinimalRebuildFromTracking>
        <WarningLevel Condition="'%(WarningLevel)' == 'Level1' or '%(WarningLevel)' == 'Level2' or '%(WarningLevel)' == 'Level3'">EnableAllWarningsWarningLevel>
        <CompileAs Condition="'%(ClCompile.CompileAs)' == 'Default' and '%(ClCompile.Extension)' == '.c'">CompileAsCCompileAs>
        <CompileAs Condition="'%(ClCompile.CompileAs)' == 'Default' and '%(ClCompile.Extension)' != '.c'">CompileAsCppCompileAs>
      ClCompile>

      <ClCompile>
        
        <CLanguageStandard Condition="'%(ClCompile.CompileAs)' == 'CompileAsCpp'">CLanguageStandard>
        <CppLanguageStandard Condition="'%(ClCompile.CompileAs)' == 'CompileAsC'">CppLanguageStandard>
        
        
        <RuntimeTypeInfo Condition="'%(ClCompile.CompileAs)' == 'CompileAsC'" />
      ClCompile>
      
      
      <ClCompile Condition="'$(DesignTimeBuild)' != 'true'">
        <AdditionalOptions Condition="'%(ClCompile.RuntimeLibrary)' == 'MultiThreaded'">%(ClCompile.AdditionalOptions) -D_MT -Xclang --dependent-lib=libcmt -Xclang --dependent-lib=oldnamesAdditionalOptions>
        <AdditionalOptions Condition="'%(ClCompile.RuntimeLibrary)' == 'MultiThreadedDebug'">%(ClCompile.AdditionalOptions) -D_DEBUG -D_MT -Xclang --dependent-lib=libcmtd -Xclang --dependent-lib=oldnamesAdditionalOptions>
        <AdditionalOptions Condition="'%(ClCompile.RuntimeLibrary)' == 'MultiThreadedDLL'">%(ClCompile.AdditionalOptions) -D_MT -D_DLL -Xclang --dependent-lib=msvcrt -Xclang --dependent-lib=oldnamesAdditionalOptions>
        <AdditionalOptions Condition="'%(ClCompile.RuntimeLibrary)' == 'MultiThreadedDebugDLL'">%(ClCompile.AdditionalOptions) -D_DEBUG -D_MT -D_DLL -Xclang --dependent-lib=msvcrtd -Xclang --dependent-lib=oldnamesAdditionalOptions>
      ClCompile>
    ItemGroup>
  Target>

  <Target Name="ClCompile"
          Condition="'@(ClCompile)' != ''"
          DependsOnTargets="SelectClCompile" >

    <PropertyGroup>
      <CLToolArchitecture Condition="'$(CLToolArchitecture)' == ''">$(VCToolArchitecture)CLToolArchitecture>
      <CLDeleteOutputOnExecute Condition="'$(CLDeleteOutputOnExecute)' == ''">trueCLDeleteOutputOnExecute>
      <ClMutliToolTaskMinimalRebuild>trueClMutliToolTaskMinimalRebuild>
      <ClMutliToolTaskMinimalRebuild Condition="'$(_BuildActionType)' != 'Build' or '$(ForceRebuild)' == 'true'">falseClMutliToolTaskMinimalRebuild>
      <ProcessorNumber Condition="'$(ProcessorNumber)' == ''">$(CL_MPCount)ProcessorNumber>
    PropertyGroup>

    <ItemGroup>
      <ClCompile>
        
        <AdditionalIncludeDirectories>%(ClCompile.AdditionalIncludeDirectories);$(IncludePath)AdditionalIncludeDirectories>
      ClCompile>
    ItemGroup>

    <Message Condition="'$(_DebugMessages)' == 'true'" Importance="high" Text="ClCompilePCH = '@(ClCompilePCH)'"/>
    <Message Condition="'$(_DebugMessages)' == 'true'" Importance="high" Text="ClCompilePCH.ObjectFileName = '%(ClCompilePCH.ObjectFileName)'"/>

    <MultiToolTask Condition="'%(ClCompile.ExcludedFromBuild)' != 'true' and '$(UseMultiToolTask)' == 'true'"
                  TaskName="Microsoft.Build.CPPTasks.ClangCompile"
                  TaskAssemblyName="$(VCTargetsPath)Microsoft.Build.CppTasks.Common.dll"
                  Sources="@(ClCompile)"

                  SchedulerVerbose="$(MultiToolTaskVerbose)"
                  SemaphoreProcCount="$(ProcessorNumber)"
                  TrackFileAccess="$(TrackFileAccess)"
                  TrackerLogDirectory="$(TLogLocation)"
                  MinimalRebuildFromTracking="$(ClMutliToolTaskMinimalRebuild)"
                  TLogReadFiles="@(CLTLogReadFiles)"
                  TLogWriteFiles="@(CLTLogWriteFiles)"
                  ToolExe="$(ClangToolExe)"
                  ToolPath="$(ClangToolPath)"
                  ToolArchitecture="$(CLToolArchitecture)"
                  TrackerFrameworkPath="$(CLTrackerFrameworkPath)"
                  TrackerSdkPath="$(CLTrackerSdkPath)"
                  EnableExecuteTool="$(ClangEnableExecuteTool)"
    >
    MultiToolTask>

    
    
    ClangCompile>

    
    ClangCompile>
  Target>

  <ItemGroup Condition="'$(ConfigurationType)' != 'Utility'">
    <PropertyPageSchema Condition="'$(ConfigurationType)' != 'Utility'" Include="$(VCTargetsPath)$(LangID)\clang.xml"/>
  ItemGroup>

Project>

(二)、注意事项

通过上面的修改后,基本上可以正常使用了,但是可能会有如下问题

  1. 由于是使用的VS的头文件,所以需要把MS的兼容模式打开,否则会报错,同时建议把MS的扩展支持也打开(上面的clang工具集配置已经默认打开了这两项)。
    将LLVM/Clang编译器整合到Visual Studio中_第9张图片
  2. 由于clang默认是不会生成VS调试器可识别的PDB格式,所以要使用VS调试clang生成的程序,需要让Clang生成PDB格式的调试信息,添加:

-g -gcodeview

即可(上面的clang工具集配置已经默认添加了该参数)。

  1. 如果预编译头文件带路径,需要把路径写全;Clang不需要使用某个CPP来单独创建,直接在项目属性中设置需要使用的预编译头即可。
    将LLVM/Clang编译器整合到Visual Studio中_第10张图片
  2. 报错:C:\Program Files (x86)\Windows Kits\8.1\Include\um\combaseapi.h(229,21): error : unknown type name ‘IUnknown’
    将LLVM/Clang编译器整合到Visual Studio中_第11张图片
    可以直接在模板前面添加一个声明:
extern "C++"
{
	interface IUnknown;  // 这里添加一个声明,以免Clang编译器报错
    template<typename T> _Post_equal_to_(pp) _Post_satisfies_(return == pp) void** IID_PPV_ARGS_Helper(T** pp) 
    {
#pragma prefast(suppress: 6269, "Tool issue with unused static_cast")
        static_cast<IUnknown*>(*pp);    // make sure everyone derives from IUnknown
        return reinterpret_cast<void**>(pp);
    }    
}
  1. 关于Boost库的使用
  • 如果要使用Boost,需要定义宏:
BOOST_USE_WINDOWS_H
  • 如果在自己的静态库中使用Boost的静态thread库,需要定义宏:
BOOST_THREAD_USE_LIB

否则在exe项目中使用自己的静态库时会出现链接错误。

error LNK2001: 无法解析的外部符号 "__declspec(dllimport) public: __cdecl boost::thread::~thread(void)" (__imp_??1thread@boost@@QEAA@XZ)
error LNK2019: 无法解析的外部符号 "__declspec(dllimport) private: void __cdecl boost::thread::start_thread(void)" (__imp_?start_thread@thread@boost@@AEAAXXZ)
error LNK2019: 无法解析的外部符号 "__declspec(dllimport) public: void __cdecl boost::thread::join(void)" (__imp_?join@thread@boost@@QEAAXXZ)
  • 如果使用的是Windows8.1的SDK,项目中原来定义了宏:
_WIN32_WINNT=0x0501

需要删除,或者定义成

_WIN32_WINNT=0x0600

否则会出现错误

boost_1_58_0\boost\thread\win32\thread_primitives.hpp(75,21): error : no member named 'GetTickCount64' in the global namespace; did you mean 'GetTickCount'?
              using ::GetTickCount64;
                    ~~^
  C:\Program Files (x86)\Windows Kits\8.1\Include\um\sysinfoapi.h(203,1): note: 'GetTickCount' declared here
  GetTickCount(
  ^
  In file included from :1:

参见C:\Program Files (x86)\Windows Kits\8.1\Include\um\sysinfoapi.h(221,1)中GetTickCount64定义:

#if (_WIN32_WINNT >= 0x0600)
WINBASEAPI
ULONGLONG
WINAPI
GetTickCount64(
    VOID
    );
#endif
  • Boost1.58版会报错:
boost\thread\win32\thread_primitives.hpp(225,67): error : functions that differ only in their return type cannot be overloaded

将LLVM/Clang编译器整合到Visual Studio中_第12张图片
可以在thread_primitives.hpp代码:

#if BOOST_PLAT_WINDOWS_RUNTIME
#include 
#endif

的前面添加如下代码:

#if __clang__
#ifdef BOOST_PLAT_WINDOWS_RUNTIME
#undef BOOST_PLAT_WINDOWS_RUNTIME
#define BOOST_PLAT_WINDOWS_RUNTIME 1
#endif
#endif

通过这些修改就大功告成了,当然如果使用其它第三方库,可能会遇到一些问题,就需要自行探索解决了。

祝玩得开心,如果喜欢本文请记得点赞哦!

你可能感兴趣的:(LLVM/Clang)