【问题标题】:How does Visual Studio determine the output path when it's not informed in the .csproj file?.csproj 文件中未通知时,Visual Studio 如何确定输出路径?
【发布时间】:2015-01-20 07:31:09
【问题描述】:

我正在尝试从另一个解决方案中引用一个 C# DLL 项目,但是构建正在一个非常奇怪的输出文件夹中生成 DLL。

目录内容是这样的:

c:\a\b\c\src\Solution.sln
c:\a\x\y\z\MyDLL\MyDLL.csproj

MyDLL.csproj 没有<OutputPath> 标记。但是它确实有一个我不经常看到的 标签。

属性视图中显示的计算输出路径恰好是:

..\..\..\..\b\c\src-z\MyDLL\objd\i386

这对应于这个路径:

c:\a\b\c\src-z\src\MyDLL\objd\i386

这很奇怪,因为我不知道 src-z 有什么配置。 Visual Studio 是否计算带有连字符的路径?

我想解决这个问题,可能会更改 ,但我不想破坏其他解决方案。

计算似乎发生在构建过程的早期,因为构建器记录的第一件事是:

1>Project 'MyDLL (x\y\z\MyDLL\MyDLL.csproj)' is not up to date.
  Input file 'x\y\z\MyDLL\MyDLL.csproj' is modified after output
  file 'c:\a\b\c\src-z\src\MyDLL\objd\i386\MyDLL.pdb'.

那么当项目 标签找不到时,Visual Studio 使用什么算法来计算输出路径?

【问题讨论】:

  • 这可能是Nuget引起的问题
  • “属性视图中显示的计算输出路径恰好是” - 您是否尝试过简单地将输出路径设置为您想要的?
  • 可能不相关,但我为自己制定的一条规则是,在同一解决方案中从另一个项目引用 .dll 时,永远不要使用“解决方案引用”。我总是使用对 .dll 文件的直接引用,并在 Visual Studio 中使用解决方案的项目依赖项来强制执行正确的构建顺序。这样做的原因是,当 MSBuild 在 Visual Studio 之外(例如在持续集成或增量构建系统中)直接使用 .csproj 文件时,MSBuild 遵循进程间引用并可能执行您不执行的构建期待。
  • 使用诊断冗长可能会显示值的来源(我认为是工具->选项->构建和运行)
  • @stijn 做到了。这就是我获得上述构建器日志的方式。

标签: c# visual-studio visual-studio-2012 msbuild csproj


【解决方案1】:

我会说你在某处有一个 OutputPath 声明,但如果不是在你的 .csproj 文件中的一个导入的目标文件中。

我将把我的答案分成几个部分:

  1. 标签并更改它。
    使用此标记,您可以声明解决方案目录变量 $(SolutionDir),但如果它与解决方案实际所在的位置不同,我认为 Visual Studio 不会从 .csproj 文件内部使用它。
    但是该标签可以被 MSBuild 构建使用。如果我在 .csproj 文件中声明它,我无法让 Visual Studio 使用它。
    Visual Studio 使用已加载解决方案的目录作为变量内容,而不是我的测试中 .csproj 文件中的任何不同声明。
    话虽如此:更改标签可能会更改 $(SolutionDir) 变量在您使用它的任何地方(如 PreBuild/PostBuild 或输出目录)的使用。无论在哪里使用。但不是在 Visual Studio 中。
    如果不使用更改,则在 Visual Studio 构建中不会有太大变化。

  2. 无输出路径标记
    如果在 Visual Studio 中加载了 .csproj 文件,我会期望这个标签。但是可以在目标文件而不是 .csproj 文件中声明它。因此,您还必须检查导入的目标文件。
    例如查看文件 Microsoft.CSharp.targets。这是 Visual Studio 中 CS-Projects 的标准导入目标文件。它对 OutputPath 进行计算和声明。
    第二种可能是您自己可以导入的目标文件(手写的 .csproj 文件)。那里也可以声明。
    第三种可能性:我认为可以通过 MSBuild 的命令行参数声明此变量,但不适用于 Visual Studio。

  3. 在 .csproj 文件中没有此标记时,Visual Studio 是否可以工作?
    通常不会,但您可以声明覆盖标准 C# 目标文件 (Microsoft.CSharp.targets) 中的错误并使其构建 - 但随后在此文件中声明。
    如果未声明,标准输出目录将是 Microsoft.CSharp.targets 定义的 \bin\Debug(用于调试版本)。
    否则你会得到一个错误。缺少 OutputPath 声明。

  4. 如何计算 查看 .csproj 文件和目标文件(不包括 MSBuild 中的命令行参数)并查看哪些 PropertyGroup 部分有效(检查条件)。 例如:



    其中的所有内容都对所选配置 Debug 和 AnyCPU 有效。特别是在标准目标文件中,有一些 OutputPath 的声明。 如果您的信息正确,这似乎对您来说是非标准的:通常如果没有声明 OutputPath,您会在 Visual Studio 构建中收到错误,因为有一个部分 在目标中检查声明并引发错误(您可以更改此行为 - 参见第 3 点)。解释将像任何脚本一样自上而下。

  5. src-z 来自哪里? (在 Visual Studio 中)
    扫描您用于“src-z”的所有 .csproj 文件和目标文件以及解决方案文件的硬盘位置,以找出它的来源。

如果您真的在任何地方都没有任何 OutputPath 声明,那么我无法解释您的 VS-Build 工作的原因。
如果您没有找到 src-z,那么您能否发布更多关于您的 .csproj 文件以及您如何使用它(Visual Studio 和解决方案)的信息?

【讨论】:

    【解决方案2】:

    我发现了问题。引用的项目之一是将 定义为 $SolutionDir + "-" + $ProjectName,从而产生 c:\a\b\c\src-z

    至于回答我的问题,我能推断的最好的是:

    1. 如果有 ,则使用它。
    2. 否则,输出路径定义为 + + "bin"。
    3. 的默认值为项目目录。
    4. 的默认值由构建类型(即调试、发布等)定义。

    【讨论】:

      【解决方案3】:

      可以在C:\Program Files (x86)\MSBuild\12.0\Bin\Microsoft.Common.CurrentVersion.targets 中找到填充OutputPath 的代码(默认情况下;如果MSBuild 安装目录不同,它可能会改变)。

      有一条评论说:

      输出目录:

      表示项目或解决方案的最终输出位置。在构建解决方案时,OutDir 可用于在一个位置收集多个项目输出。此外,OutDir 包含在用于解析引用的 AssemblySearchPaths 中。

      输出路径:

      该属性通常在项目文件中指定,用于初始化OutDir。 OutDir 和 OutputPath 因遗留原因而有所区别,应尽可能使用 OutDir。

      因此,虽然 OutputPath 经常被引用,但真正重要的是 OutDir。如果没有设置平台或配置,则 OutputPath 设置为bin\Debug\

      如果我们查看该文件,我们可以看到设置OutDir 的逻辑非常简单。如果未设置OutDir,则将其设置为OutputPath。如果设置了GenerateProjectSpecificOutputPath,则将一个以项目命名的文件夹附加到路径中会有一些额外的逻辑。

      查看Microsoft.CSharp.targetsMicrosoft.CSharp.CurrentVersion.targetsMicrosoft.Common.TargetsMicrosoft.Common.CurrentVersion.targetsOutDirOutputPath 似乎都没有设置在其他任何地方。因此,假设一个“开箱即用”的 C# 项目,它基本上等于 OutDirOutputPathbin\Debug

      最后一点相关的信息是工作目录。 OutDir 可以是相对路径,在这种情况下它将位于工作目录中的某个位置。

      至于BaseIntermediateOutputPath,信息在同一个文件中:

      BaseIntermediateOutputPath:

      这是将创建所有配置特定中间输出文件夹的顶级文件夹。默认值为 obj\

      中间输出路径:

      这是完整的中间输出路径,如果未指定(例如 obj\debug),则从 BaseIntermediateOutputPath 派生。如果此属性被覆盖,则设置 BaseIntermediateOutputPath 无效。

      查看逻辑,如果未设置,则默认为obj\(注意,相对路径,因此工作目录再次发挥作用)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-09
        • 1970-01-01
        • 2011-08-18
        • 1970-01-01
        • 2021-11-11
        • 1970-01-01
        • 2016-12-07
        相关资源
        最近更新 更多