原本我是使用批处理调用 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. jQuery学习之路(3)- 事件

    ▓▓▓▓▓▓ 大致介绍 jQuery增加了并扩展了基本的事件处理机制,不但提供了更加优雅的事件处理语法,而且极大地增强了事件处理能力 ▓▓▓▓▓▓ jQuery中的事件 ▓▓▓▓▓▓ 加载DOM 在j ...

  2. 利用Node.js的Net模块实现一个命令行多人聊天室

    1.net模块基本API 要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用.NET模块API分为两大类:Server和Socket类.工厂方法. Server类 ...

  3. 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)

    本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...

  4. CSS 3学习——transition 过渡

    以下内容根据官方规范翻译以及自己的理解整理. 1.介绍 这篇文档介绍能够实现隐式过渡的CSS新特性.文档中介绍的CSS新特性描述了CSS属性的值如何在给定的时间内平滑地从一个值变为另一个值. 2.过渡 ...

  5. PHP类和对象之重载

    PHP中的重载指的是动态的创建属性与方法,是通过魔术方法来实现的.属性的重载通过__set,__get,__isset,__unset来分别实现对不存在属性的赋值.读取.判断属性是否设置.销毁属性. ...

  6. System.Guid ToString五中格式

    参考:https://msdn.microsoft.com/en-us/library/97af8hh4.aspx 测试代码: using System; using System.Collectio ...

  7. phpstorm 配置 xdebug调试工具

    前言   php是脚本型程序 每次出错都要手动exit断点程序不是很方便 哪里有需求哪里就有生产,Xdebug可以实现对php的断点调试.下面将我个人的安装经历分享给大家. 运行环境 windows ...

  8. Struts的文件上传下载

    Struts的文件上传下载 1.文件上传 Struts2的文件上传也是使用fileUpload的组件,这个组默认是集合在框架里面的.且是使用拦截器:<interceptor name=" ...

  9. 我的MYSQL学习心得(五) 运算符

    我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  10. 使用Hystrix提高系统可用性

    今天稍微复杂点的互联网应用,服务端基本都是分布式的,大量的服务支撑起整个系统,服务之间也难免有大量的依赖关系,依赖都是通过网络连接起来. (图片来源:https://github.com/Netfli ...