原本我是使用批处理调用 MSBuild 完成解决方案编译的,新版的 MSBuild 在 Visual Studio 2015 会自带安装.

当然在Visual Studio 2015 中,MSBuild 是一个独立的安装包,可以单独安装,而无须安装 Visual Studio 2015.

刚开始,我在 Windows Server 2008 R2 上使用 MSBuild 编译使用 .NET Framework 4.5.2 版本 开发的项目,也不是那么顺利的.

期间,遇到并且解决了很多问题,依次顺序为:

1. Windows Server 2008 R2 没有安装 .NET Framework 4.5.2 ,这个安装 .NET Framework 4.5.2 就解决了.

2. Windows Server 2008 R2 上没有可以编译 .NET Framework 4.5.2 版本项目的  MSBuild .

原因是 MSBuild 的版本问题,因为 .NET Framework 4.0 自带的 MSBuild 不能识别 C# 6.0 语法特性.

对于这个问题,当时很纠结,因为那时我还不知道 MSBuild 有了独立安装包,以为想要用新版的 MSBuild 必须在服务器上安装 Visual Studio 2015.

后来我在visualstudio.com上找到了 MSBuild 独立安装包, 名为 Microsoft Build Tools 2015, 所以这个问题也算是解决了.

3. 在Windows Server 2008 R2 上用 MSBuild 2015 居然要安装 .NET Framework 4.5.2 SDK ?

这个也是安装 .NET Framework 4.5.2 Developer Pack 就可以解决了, 不过我没安装, 而是直接从本机上拷贝一份到服务器上, 存放位置和本机的路径一样.

只要安装了 Visual Studio 2015 ,那么 SDK 的位置一般在(x86系统)C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2 ,

(x64系统)C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2.

4. 由于在项目中引用了第三方组件,而第三方组件又引用了一些 .NET Framework 4.0 的 dll, 而在引用第三方组件的项目中没有引用第三方组件中引用了的 .NET Framework 4.0 的 dll.

一般情况下,用 Visual Studio 2015 进行编译是没有问题的. 当使用批处理进行编译的时候, 问题就来了, 抛出了一对错误, 诸如 System.Object, Object 之类的错误, 比如:

error CS0012: The type 'Object' is defined in an assembly that is not referenced.
    You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral,
    PublicKeyToken=b03f5f7f11d50a3a'.

The type 'System.Object' is defined in an assembly
    that is not referenced. You must add a reference to assembly 'System.Runtime,
    Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

发现同一依赖程序集的不同版本之间存在冲突

解决办法就是在引用了第三方组件的项目中, 引用第三方组件中引用了的 .NET Framework 4.0 的 dll. 这样批处理是可以成功执行完成编译的了. 但 Visual Studio 2015 编译却报错了.

于是折腾了一番, 敲定解决办法是:

1.拷贝System.Runtime.dll到解决方案目录(随意, 我的是Library目录)下.

2.直接打开需要引用的csproj文件,向其中添加:

<Reference Include="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<HintPath>..\..\Library\System.Runtime.dll</HintPath>
<Private>True</Private>
</Reference>

3.向 Web.Config 的 runtime --> assemblyBinding 节添加:

<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>

到这里, VS 编译 和 批处理编译都没问题了.

MSBuild 批处理编译 .NET Framework 4.5.2 项目的命令行:

ECHO 初始化变量
SET ProgramPath="C:\Program Files"
IF EXIST %windir%\SysWOW64 SET ProgramPath="C:\Program Files (x86)"
SET MsBuildExe="%ProgramPath%\MSBuild\14.0\Bin\MSBuild.exe" /t:rebuild /verbosity:q /p:Configuration=Release;FrameworkPathOverride="%ProgramPath%\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2" /l:FileLogger,Microsoft.Build.Engine;verbosity=normal;encoding=utf-8;append=true;logfile=Build.log ECHO 编译解决方案
%MsBuildExe% "C:\work\CRM\CRM.VS2015.sln"

大功告成, 这样就可以编译 .NET Framework 4.5.2 项目了.

可是后来我为什么要换成 roslyn 编译呢? 这也是有原因的!

经过上面的折腾,我成功用批处理编译 .NET Framework 4.5.2 项目后, 我并未满足, 我想要更方便的, 无须安装那么多操蛋的东西, 只需要有运行时环境就可以了, 行不行?

答案当然是可以的, 那便是近年渐火的 roslyn 开源项目.

接下来, 我尝试使用 roslyn 帮助我完成编译 .NET Framework 4.5.2 项目.

首先, 用 Visual Studio 2015 Update 1 新建一个目标框架为 .NET Framework 4.5.2 的控制台 C# 项目, 为什么一定要 Update 1, 不解释, 照做就对了.

然后对这项目右键属性, 更改程序集名称为 RBuild .

其次, 在 Visual Studio 菜单栏中 工具 --> NuGet 包管理器  --> 程序包管理器控制台.

在控制台输入指令: Install-Package Microsoft.CodeAnalysis 以及 Install-Package Microsoft.Net.Compilers.

安装成功后,在项目中会有个包管理文件 packages.config

内容如下:

<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.CodeAnalysis" version="1.1.1" targetFramework="net452" />
<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net452" />
<package id="Microsoft.CodeAnalysis.Common" version="1.1.1" targetFramework="net452" />
<package id="Microsoft.CodeAnalysis.CSharp" version="1.1.1" targetFramework="net452" />
<package id="Microsoft.CodeAnalysis.CSharp.Workspaces" version="1.1.1" targetFramework="net452" />
<package id="Microsoft.CodeAnalysis.VisualBasic" version="1.1.1" targetFramework="net452" />
<package id="Microsoft.CodeAnalysis.VisualBasic.Workspaces" version="1.1.1" targetFramework="net452" />
<package id="Microsoft.CodeAnalysis.Workspaces.Common" version="1.1.1" targetFramework="net452" />
<package id="Microsoft.Composition" version="1.0.27" targetFramework="net452" />
<package id="Microsoft.Net.Compilers" version="1.1.1" targetFramework="net452" developmentDependency="true" />
<package id="System.Collections" version="4.0.0" targetFramework="net452" />
<package id="System.Collections.Immutable" version="1.1.37" targetFramework="net452" />
<package id="System.Diagnostics.Debug" version="4.0.0" targetFramework="net452" />
<package id="System.Globalization" version="4.0.0" targetFramework="net452" />
<package id="System.IO" version="4.0.0" targetFramework="net452" />
<package id="System.Linq" version="4.0.0" targetFramework="net452" />
<package id="System.Reflection" version="4.0.0" targetFramework="net452" />
<package id="System.Reflection.Extensions" version="4.0.0" targetFramework="net452" />
<package id="System.Reflection.Metadata" version="1.1.0" targetFramework="net452" />
<package id="System.Reflection.Primitives" version="4.0.0" targetFramework="net452" />
<package id="System.Resources.ResourceManager" version="4.0.0" targetFramework="net452" />
<package id="System.Runtime" version="4.0.0" targetFramework="net452" />
<package id="System.Runtime.Extensions" version="4.0.0" targetFramework="net452" />
<package id="System.Runtime.InteropServices" version="4.0.0" targetFramework="net452" />
<package id="System.Text.Encoding" version="4.0.0" targetFramework="net452" />
<package id="System.Text.Encoding.Extensions" version="4.0.0" targetFramework="net452" />
<package id="System.Threading" version="4.0.0" targetFramework="net452" />
</packages>

接着, 在 Program类 敲代码:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.MSBuild;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq; namespace WebAPI.Build.Roslyn
{
class Program
{
/// <summary>
/// 待写入文件的log列表
/// </summary>
static List<string> Logs = new List<string>(); /// <summary>
/// 输出文件,成功与否
/// </summary>
static Dictionary<string, bool> OutputFiles = new Dictionary<string, bool>(); static void Main(string[] args)
{
//命令行参数解析器
CommandLineArgumentParser arguments = CommandLineArgumentParser.Parse(args); if (arguments.Has(ConfigInfo.Help) || arguments.Has(ConfigInfo.Question))
{
string helpFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "help.txt");
string[] contents = File.ReadAllLines(helpFile);
foreach (string content in contents)
{
Console.WriteLine(content);
} return;
} //解决方案路径
string solutionUrl;
if (arguments.Has(ConfigInfo.SolutionUrl))
{
solutionUrl = arguments.Get(ConfigInfo.SolutionUrl).Next;
}
else
{
solutionUrl = GetAppSetting(ConfigInfo.SolutionUrl);
} //输出目录
string outputDir;
if (arguments.Has(ConfigInfo.OutputDir))
{
outputDir = arguments.Get(ConfigInfo.OutputDir).Next;
}
else
{
outputDir = GetAppSetting(ConfigInfo.OutputDir);
} //编译属性
string properties;
if (arguments.Has(ConfigInfo.Properties))
{
properties = arguments.Get(ConfigInfo.Properties).Next;
}
else
{
properties = GetAppSetting(ConfigInfo.Properties);
} Dictionary<string, string> keyValues;
if (!string.IsNullOrEmpty(properties))
{
keyValues = new Dictionary<string, string>();
IEnumerable<string> props = properties.Split(';').Where(t => !string.IsNullOrWhiteSpace(t));
foreach (var item in props)
{
string[] prop = item.Split('=');
keyValues.Add(prop[], prop[]);
}
}
else
{
keyValues = null;
} string logFile;
if (arguments.Has(ConfigInfo.LogFile))
{
logFile = arguments.Get(ConfigInfo.LogFile).Next;
}
else
{
logFile = GetAppSetting(ConfigInfo.LogFile);
} if (!File.Exists(solutionUrl))
{
AddFormatPrint("The file specified does not exist.");
AddFormatPrint("FileName:" + solutionUrl);
}
else
{
AddFormatPrint("Start building solutions");
AddFormatPrint(); AddFormatPrint("Check output directory exists");
if (!Directory.Exists(outputDir))
{
AddFormatPrint("Create output directory:");
AddFormatPrint(outputDir);
Directory.CreateDirectory(outputDir);
AddFormatPrint("Output directory has been created successfully");
}
else
{
AddFormatPrint("Output directory already exists");
}
AddFormatPrint(); AddFormatPrint("Start compilation solution");
AddFormatPrint();
bool success = CompileSolution(solutionUrl, outputDir, keyValues);
AddFormatPrint(); if (success)
{
AddFormatPrint("Compilation completed successfully.");
}
else
{
AddFormatPrint("Compilation failed.");
}
} foreach (string fullPathName in OutputFiles.Where(t => t.Value == false).Select(t => t.Key))
{
try
{
File.Delete(fullPathName);
}
catch
{
}
}
File.WriteAllLines(logFile, Logs); #if DEBUG
AddFormatPrint("Press the any key to exit.");
Console.ReadKey();
#endif
} /// <summary>
/// 编译解决方案和输出项目bin文件
/// </summary>
/// <param name="solutionUrl"></param>
/// <param name="outputDir"></param>
/// <param name="keyValues"></param>
/// <returns></returns>
private static bool CompileSolution(string solutionUrl, string outputDir, Dictionary<string, string> keyValues = null)
{
bool success = true; MSBuildWorkspace workspace;
if (keyValues != null && keyValues.Any())
{
workspace = MSBuildWorkspace.Create(keyValues);
}
else
{
workspace = MSBuildWorkspace.Create();
} Solution solution = workspace.OpenSolutionAsync(solutionUrl).Result; ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph();
foreach (ProjectId projectId in projectGraph.GetTopologicallySortedProjects())
{
Project project = solution.GetProject(projectId);
AddFormatPrint("Building: {0}", project.FilePath);
try
{
Compilation projectCompilation = project.GetCompilationAsync().Result;
if (null != projectCompilation && !string.IsNullOrEmpty(projectCompilation.AssemblyName))
{
string fileName = string.Format("{0}.dll", projectCompilation.AssemblyName);
string fullPathName = string.Format("{0}\\{1}", outputDir, fileName);
if (!OutputFiles.ContainsKey(fullPathName))
{
OutputFiles.Add(fullPathName, true);
} var diagnostics = projectCompilation.GetDiagnostics();
var warnDiagnostics = diagnostics.Where(x => x.Severity == DiagnosticSeverity.Warning).ToArray();
var errorDiagnostics = diagnostics.Where(x => x.Severity == DiagnosticSeverity.Error).ToArray(); foreach (var e in errorDiagnostics.Concat(warnDiagnostics).ToArray())
{
AddFormatPrint("{0}: {1}", e.Severity.ToString(), e.ToString());
} if (errorDiagnostics.Any())
{
OutputFiles[fullPathName] = false;
AddFormatPrint("Build failed.");
success = false;
}
else
{
AddFormatPrint("Build successfully."); using (var stream = new MemoryStream())
{
EmitResult result = projectCompilation.Emit(stream);
AddFormatPrint("{0} --> {1}", project.Name, fullPathName);
if (result.Success)
{
using (FileStream file = File.Create(fullPathName))
{
stream.Seek(, SeekOrigin.Begin);
stream.CopyTo(file);
}
AddFormatPrint("Output successfully.");
}
else
{
OutputFiles[fullPathName] = false;
AddFormatPrint("Output failed.");
success = false;
}
}
}
AddFormatPrint();
}
else
{
AddFormatPrint("Build failed. {0}", project.FilePath);
success = false;
}
}
catch (AggregateException ex)
{
foreach (var ie in ex.InnerExceptions)
{
AddFormatPrint(ie.Message);
}
success = false;
}
catch (Exception ex)
{
AddFormatPrint(ex.Message);
success = false;
}
AddFormatPrint();
} return success;
} /// <summary>
/// 添加消息记录和打印消息
/// </summary>
/// <param name="format"></param>
/// <param name="args"></param>
private static void AddFormatPrint(string format = "", params object[] args)
{
if (format == string.Empty)
{
Logs.Add(string.Empty);
Console.WriteLine();
}
else
{
string log = string.Format(format, args);
Logs.Add(log);
Console.WriteLine(log);
}
} /// <summary>
/// 获取配置值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static string GetAppSetting(string key)
{
return ConfigurationManager.AppSettings[key] ?? ConfigurationManager.AppSettings[ConfigInfo.KeyValues[key]];
}
} public struct ConfigInfo
{
/// <summary>
/// 解决方案路径
/// </summary>
public const string SolutionUrl = "-s"; /// <summary>
/// 输出目录
/// </summary>
public const string OutputDir = "-o"; /// <summary>
/// 编译属性
/// </summary>
public const string Properties = "-p"; /// <summary>
/// 日志文件名称
/// </summary>
public const string LogFile = "-l"; /// <summary>
/// 帮助
/// </summary>
public const string Help = "-h"; /// <summary>
/// 提问
/// </summary>
public const string Question = "-?"; /// <summary>
/// 全称键值对
/// </summary>
public static readonly Dictionary<string, string> KeyValues = new Dictionary<string, string> { { SolutionUrl, "solutionUrl" }, { OutputDir, "outputDir" }, { Properties, "properties" }, { LogFile, "logFile" } };
}
}

编译完成后, 就可以在 CMD 命令行提示符用了.

这是 help.txt 内容以及用法:

Provide help information for commands.

RBuild  [-s] [-o] [-p]

        -s —— Solution Path, required.
Use: -s "C:\work\CRM\CRM.VS2015.sln"
-o —— Output Directory, required.
Use: -o "E:\work\CRM\Build\WebAPI\bin"
-p —— Build Properties, required.
Use: -p Configuration=Release;FrameworkPathOverride=C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2;key=value
-l —— Output Log Path, not required.
Use: -l "log.txt"

目前我只知道 roslyn 可以编译项目, 但编译后拷贝相关的非代码文件到相应目录这个功能却没有发现哪里有, 只能通过批处理自己拷贝了.

我的用法

ECHO 开始编译解决方案
BuildTools\RBuild.exe -s "..\..\CRM\src\CRM.VS2015.sln" -o "CRM\bin" -p Configuration=Release -l Build.log

安装包下载:

.NET Framework 4.5.2(运行时环境):https://www.microsoft.com/zh-cn/download/details.aspx?id=42642

.NET Framework 4.5.2 Language Pack(可选):https://www.microsoft.com/zh-cn/download/details.aspx?id=42641

.NET Framework 4.5.2 Developer Pack(SDK):https://www.microsoft.com/zh-CN/download/details.aspx?id=42637

Microsoft Build Tools 2015(MSBuild):https://www.microsoft.com/zh-cn/download/details.aspx?id=48159

引用资料:

http://www.cnblogs.com/walkerwang/p/3368986.html

http://yangpei.appsp0t.com/post/aglzfnlhbmdwZWlyDAsSBUVudHJ5GKEfDA

http://stackoverflow.com/questions/13280008/how-do-i-compile-a-c-sharp-solution-with-roslyn

http://www.cnblogs.com/linxuanchen/p/c-sharp-command-line-argument-parser.html

https://msdn.microsoft.com/zh-cn/library/ms164311.aspx

https://github.com/dotnet/roslyn

使用roslyn代替MSBuild完成解决方案编译的更多相关文章

  1. win10 uwp 使用 msbuild 命令行编译 UWP 程序

    原文:win10 uwp 使用 msbuild 命令行编译 UWP 程序 版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问.如果当前博客图片看不到,请到 http:// ...

  2. 利用批处理结合Msbuild实现快速编译

    我们经常在用vs2005做项目的时候会把一个项目分成几个模块(不管是对于功能上,还是系统构架上面),为的是以后部署,还有修改维护时候的方便.这样就会带来一个问题,随着模块的增加(这里所说得每个模块就是 ...

  3. 每日踩坑 2019-04-08 VS2015未能找到路径“…\bin\roslyn\csc.exe”的解决方案

    使用 Nuget 安装 Microsoft.CodeDom.Providers.DotNetCompilerPlatform 包即可. VS2017都是用 roslyn 编译, VS2015原本的编译 ...

  4. [2015-11-10]分享一个调用msbuild生成解决方案并打包发布的批处理脚本

    最近工作成果之一,特此记录. 用于打包的批处理脚本 注意设置 path/to/your/solutionfile.sln 指向vs的解决方案文件. setlocal enabledelayedexpa ...

  5. VS2017 Pro未能找到路径“……\bin\roslyn\csc.exe”的解决方案

    VS2017改用roslyn编译的,新的roslyn编译器,支持c# 6.0语法.它放到bin里面去是为了支持asp.net应用的动态编译. 它是通过nuget的包Microsoft.CodeDom. ...

  6. CMake生成OpenCV解决方案&&编译OpenCV源码

    生成OpenCV工程需要用到CMake,所以第一步需要下载CMake软件,下载链接:CMake下载 目前最新的版本是3.7.1,这里选择下载Platform下的Windows win32-x86 ZI ...

  7. Win10 OpenCV3.3.0+VS2013配置大坑,OpenCV解决方案编译报错“找不到python36_d.lib”错误

    今天因为想要用OpenCV做图像识别,小白一个,在网上找到一个教程,但是需要配置OpenCV3.3.0的环境,于是又在网上找OpenCV3.3.0+VS2013(因为我之前已经安过了VS2013),前 ...

  8. asyncio NetMQ 解决方案编译问题

    程序集代码 (原) <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <VersionPrefix& ...

  9. GitLab CI持续集成配置方案(补)

    上篇文章介绍了GitLab CI的持续集成配置方法,本篇文章将主要介绍NUnit的持续集成和遇到的一些坑 1.NUnit单元测试持续集成 下载NUnit.3.4.1.msi,https://githu ...

随机推荐

  1. SQL Server-聚焦UNIOL ALL/UNION查询(二十三)

    前言 本节我们来看看有关查询中UNION和UNION ALL的问题,简短的内容,深入的理解,Always to review the basics. 初探UNION和UNION ALL 首先我们过一遍 ...

  2. 开源一款简单清爽的日历组件,JavaScript版的

    源码会在最后给出地址,需要的朋友自己去下载.最近项目需要做一个日程安排的功能,就是点击日历的某一天弹出一个录入页面,填完信息后保存当天的日程安排.有日程的日期会有不同的标记(比如加一个背景色啥的).网 ...

  3. iosselect:一个js picker项目,在H5中实现IOS的select下拉框效果

    具体文档和demo可以访问github:https://github.com/zhoushengmufc/iosselect 移动端浏览器对于select的展示样式是不一致的,ios下是类似原生的pi ...

  4. vue.js几行实现的简单的todo list

    序:目前前端框架如:vue.react.angular,构建工具fis3.gulp.webpack等等...... 可谓是五花八门,层出不穷,眼花缭乱...其实吧只要你想玩还是可以玩玩的..下面是看了 ...

  5. 基于SOA架构的TDD测试驱动开发模式

    以需求用例为基,Case&Coding两条线并行,服务(M)&消费(VC)分离,单元.接口.功能.集成四层质量管理,自动化集成.测试.交付全程支持. 3个大阶段(需求分析阶段.研发准备 ...

  6. Linux常用命令

    命令格式与目录处理命令 ls 命令格式与目录处理命令 ls 命令格式:命令 [-选项][参数] 例:ls -la /etc 说明: 1)个别命令使用不遵循格式 2)当有多个选项时,可以写在一起 3)简 ...

  7. Vue.js——60分钟快速入门

    Vue.js介绍 Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的API,使得我们 ...

  8. 弄了一个支持SSL的TCP客户端

    近日需要做一些TCP的收发的调试,到网上去找TCP调试工具,找了好几款,发现不是功能不全就是不支持HEX,更重要的SSL也不支持,于是动手写了一款,叫TCPRunner,有以下特性: 使用异步IO方式 ...

  9. Windbg Extension NetExt 使用指南 【1】 ---- NetExt 介绍

    摘要 : 在使用WINDBG做debugging的时候,需要一个好的工具帮助进行数据分析. 最常见的extension包括SOS, PSSCOR.  NetExt则是另外一种提供了丰富命令功能的deb ...

  10. TODO:字节的那点事Go篇

    TODO:字节的那点事Go篇 (本文go version go1.7.3 darwin/amd64) 在Golang中string底层是由byte数组组成的. fmt.Println(len(&quo ...