Visual Studio: Làm thế nào để “Sao chép vào Thư mục đầu ra” mà không sao chép cấu trúc thư mục?


111

Tôi có một vài tệp dll trong thư mục \ lib của thư mục dự án của tôi. Trong trang thuộc tính của dll, tôi đã chọn "Build Action" là "Content" và "Copy to Output Directory" là "Copy luôn".

Sau khi xây dựng, tôi thực sự đang sao chép dll nhưng chúng nằm trong \ bin \ Release \ lib chứ không phải trong \ bin \ Release.

Có cách nào để sao chép tệp dll sang \ bin \ Release (chứ không phải vào \ bin \ Release \ lib) mà không cần viết tập lệnh sau xây dựng hoặc sử dụng nant, v.v.?

Câu trả lời:


255

thay vì <Content>sử dụng <ContentWithTargetPath>và chỉ định đường dẫn đích, như thế này:

<ItemGroup>
  <ContentWithTargetPath Include="lib\some_file.dat">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <TargetPath>some_file.dat</TargetPath>
  </ContentWithTargetPath>
<ItemGroup>

Lưu ý rằng mục nhập này có thể không hiển thị từ Visual Studio (2012, 2015, 2017), nhưng sau khi được thêm vào csproj theo cách thủ công, nó sẽ xuất hiện trong Visual Studio. Mặc dù vậy, đường dẫn đích sẽ không thể chỉnh sửa được thông qua giao diện người dùng.


2
Tôi không thấy ContentWithTargetPath như một tùy chọn Build Action trong VS 2015. Có cách nào để thêm nó không?
Kim

1
Sau khi tôi thêm mục nhập theo cách thủ công trong tệp .csproj, nó sẽ xuất hiện dưới dạng một tùy chọn trong IDE. Tuy nhiên, tôi vẫn không thể chỉnh sửa Đường dẫn mục tiêu từ IDE.
Kim

9
Lo lắng duy nhất của tôi là điều này sẽ trở nên không được hỗ trợ với các phiên bản tương lai của MSBuild / .NET / Visual Studio / Anything, vì giao diện người dùng VS2015 không hiển thị tùy chọn này hoặc thuộc tính TargetPath.
MarioDS

1
Điều này làm việc cho tôi. Không có câu trả lời nào khác phù hợp với tôi. Đây nên là câu trả lời.
GunWanderer

1
Lưu ý rằng sử dụng ContentWithTargetPathbiên dịch tăng dần ngắt (đã thử nghiệm trên VS 2017 15.9.9)
Mads Ravn

26

Giữ chúng trong đó $(ProjectDir)\Lib, nhưng thêm các tệp đó " Dưới dạng liên kết " vào thư mục gốc .csproj của bạn. Bây giờ chúng sẽ được sao chép vào bin \ Debug (hoặc bất kỳ thư mục đầu ra nào khác) mà không cần ở trong lib.

CHỈNH SỬA: Câu trả lời này đã được viết trước khi ContentWithTargetPath không có sẵn trong các phiên bản VS / MSBuild mà tôi đang sử dụng. Để câu trả lời này ở đây cho những người có thể phải sử dụng phiên bản cũ hơn của VS. Vui lòng ngừng bình luận về điều này, chúng tôi đều biết có nhiều cách tốt hơn bây giờ.


4
Cảm ơn ananthonline. Tôi đã thử các bước của bạn nhưng không giúp được gì. Có thể tôi đang làm gì đó sai. Đây là những gì tôi đang làm, vui lòng sửa nếu bạn cho rằng điều gì đó không chính xác: 1. Loại trừ những hình nền đó khỏi dự án nhưng để chúng ở trong lib 2. Nhấp chuột phải vào dự án và "Thêm các mục hiện có". Chọn các hình nền từ lib và thêm chúng "dưới dạng liên kết" 3. Nhấp chuột phải vào các hình nền và một lần nữa chọn "Copy Always" trong "Copy to Output Directory". 4. Làm sạch & Xây dựng lại. Kết quả: Tôi lại lấy được những con dlls đó trong \ bin \ release \ lib
OhDear

1
Vui lòng đăng ảnh chụp màn hình của thư mục giải pháp của bạn sau khi cấu hình nó
Ani

3
Nếu tôi cố gắng thêm một liên kết đến một tập tin đã có trong cây dự án, nó từ chối và thay vào đó chỉ bao gồm các tập tin vào dự án một lần nữa ...
Nyerguds

1
Giống như @Nyerguds, tôi đang gặp phải trường hợp bạn không thể thêm liên kết đến tệp đã có trong cây dự án nên câu trả lời này không giải quyết được câu hỏi.
Tore Østergaard

1
Nó không làm ngập thư mục gốc của dự án trong Solution Explorer? Với nhiều tệp như vậy, nó có thể là một vấn đề. Thông thường thư mục gốc của một thư mục dự án đã chứa quá nhiều tệp khác nhau.
Alex34758

10

Nếu mục đích chính của bạn là bao gồm các tệp DLL mà không làm lộn xộn thư mục gốc của dự án, thì một giải pháp khác là di chuyển các tệp DLL sang một Dự án được chia sẻ riêng biệt và thêm tệp này làm tham chiếu trong dự án gốc.

(Lưu ý rằng bài đăng này không trực tiếp trả lời câu hỏi này vì nó không bảo toàn cấu trúc thư mục và dự án, nhưng tôi thấy phương pháp này hữu ích vì tôi có thể cấu trúc lại dự án của mình trong trường hợp của mình và vì tôi muốn tránh một số nhược điểm của các cách tiếp cận khác ở đây.)

Các bước

  • Nhấp chuột phải của bạn Solution -> Add -> New Project -> Shared Project
  • Thêm DLL vào dự án này (trong thư mục gốc của dự án này, không phải trong thư mục con "lib")
  • (Kiểm tra các thuộc tính tệp DLL được đặt chính xác, ví dụ: Build Action: ContentCopy to Output Directory: Copy Always)
  • Nhấp chuột phải vào dự án gốc References -> Add Reference -> Shared Projects
  • Chọn dự án được chia sẻ bạn đã tạo trước đó

Thiết lập trông như thế này:

giải pháp-explorer-ảnh chụp màn hình


2
Cho đến nay, giải pháp đơn giản và thanh lịch để giữ cho dự án gọn gàng.
Ravi Ganesh

Tôi không thể làm cho nó hoạt động với các tệp UAP và * .bin.
Matteo

7

Thêm tệp dll làm tham chiếu đến dự án và trên tập tham chiếu "Sao chép cục bộ" thành true.


1
Cảm ơn Erik. Điều đó hoạt động hoàn hảo ngoại trừ một dll mà tôi không thể thêm làm tài liệu tham khảo. Lỗi tôi gặp phải khi thêm làm tham chiếu là Không thể thêm tham chiếu đến 'libeay32.dll'. Vui lòng đảm bảo rằng tệp có thể truy cập được và đó là cấu phần hợp lệ hoặc COM.
OhDear

7
@MAnthony: Chỉ có thể thêm hội đồng .NET hoặc hội đồng tương tác COM làm tham chiếu dự án; DLL gốc không được. Bạn sẽ cần tìm một số cách khác để sao chép DLL vào \ bin \ Release.
Michael Liu

Cảm ơn Erik và Michael và ananthonline. Xin lỗi không thể ủng hộ câu trả lời và nhận xét của bạn vì tôi không có đủ điểm danh tiếng cần thiết.
OhDear

1
Đối với DLL không được quản lý, bạn sẽ cần sử dụng phương pháp tôi đề xuất bên dưới.
Ani

4

Nếu bạn cần sao chép tệp từ thư mục Libs vào thư mục gốc VS2017:

<ItemGroup Condition="'$(Platform)' == 'x64'">
    <None Include="Libs\x64\**" Link="\%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x86'">
    <None Include="Libs\x86\**" Link="\%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

Đến bất kỳ thư mục nào khác, bao gồm cả thư mục Libs (RecursiveDir)

<ItemGroup Condition="'$(Platform)' == 'x86'">
    <None Include="Libs\x86\**" Link="mycustomfolder\%(RecursiveDir)%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

3

Có vẻ như trong VisualStudio 2015, nếu các hình nền bạn đang 'thêm bằng liên kết' nằm trong một thư mục con của cùng một dự án - chúng sẽ được tự động đặt vào một thư mục và đầu ra cũng được đặt trong một thư mục như bạn đã thấy.

Nếu các dlls nằm trong một dự án hoặc thư mục khác trên đĩa không nằm trong thư mục con của dự án , bạn có thể 'Thêm bằng liên kết' và chúng sẽ được đưa vào thư mục gốc.


Tương tự trong VS2012. Nó từ chối tạo liên kết cho chúng và chỉ thêm chúng làm nội dung. Cuối cùng, đáng buồn là giải pháp dễ dàng nhất dường như là đưa chúng vào thư mục gốc của dự án.
Nyerguds

0

Một phương pháp thay thế chỉ là để các mục dưới dạng loại None. Trong trình khám phá giải pháp, hãy nhấp vào những giải pháp bạn muốn triển khai và đặt thuộc Contenttính True.

Lưu ý: Tôi đã làm điều này trong VS2019 và mọi thứ có thể thay đổi từ phiên bản này sang phiên bản khác.

Để làm việc này, bây giờ hãy nhấp chuột phải vào dự án của bạn và chọn "Dỡ dự án". Sau đó nhấp chuột phải vào dự án chưa tải và chọn "Edit project_name.vcxproj".

Trong trình chỉnh sửa, hãy chuyển đến cuối tệp và chèn mục tiêu này ngay trước </Project>thẻ theo dõi :

  <Target Name="CopyContent" AfterTargets="Build">
    <Copy SourceFiles="@(None)" Condition="'%(None.DeploymentContent)' == 'true'" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
  </Target>

Bây giờ nhấp chuột phải vào dự án chưa tải và chọn "Tải lại dự án". Chọn để lưu và đóng nếu bạn được nhắc.

Tôi cũng đặt thành OutputDirectory:

$(SolutionDir)bin\$(Configuration)\$(Platform)\

IntermediateDirectoryđể:

$(SolutionDir)obj\$(Configuration)\$(ProjectName)\$(Platform)\

trong trang Chung Thuộc tính Dự án. Điều này đặt đầu ra trong một thư mục "bin" và trung gian trong một thư mục "obj" trong thư mục gốc của giải pháp của bạn.

Lưu ý: $(SolutionDir)Không được xác định khi bạn chạy MSBuild từ dòng lệnh. Có một thủ thuật bạn có thể sử dụng để xác định điều đó cho thư mục chứa tệp .sln bằng cách sử dụng GetDirectoryNameOfFileAbove. (còn lại như một bài tập cho người đọc). Ngoài ra, có vẻ như vào năm 2019, họ vẫn đang xử lý điều này một cách chính xác trên dòng lệnh. Yeah :)$(SolutionDir)chứa một dấu gạch chéo ngược ở cuối, do đó không có sau nó. Kết quả của mỗi kết quả phải có một dấu gạch chéo ngược ở cuối.

Bây giờ, nếu bạn sở hữu Pro trở lên, vui lòng không làm điều này mỗi khi bạn cần tạo một dự án. Điều đó sẽ là khập khiễng. Thay vào đó, khi bạn đã thiết lập dự án theo cách bạn thích, hãy chọn Project -> Export Template. Bạn đặt tên cho nó và lần sau khi bạn muốn tạo một dự án giống như dự án đó, chỉ cần chọn tên đó trong hộp thoại Dự án mới. (Trong phiên bản cũ hơn, tôi nghĩ rằng đây là Files -> Export Teamplate....)


-1

Tôi đã gặp sự cố tương tự với Visual Studio 2010 / C # Project.

Đối với các hợp ngữ (tức là có giao diện .NET), hãy sử dụng thư mục "Tham chiếu" trong dự án của bạn trong Giải pháp Explorer. Nhấp chuột phải vào nó, chọn "Thêm mục hiện có" và xác định vị trí lắp ráp .dll của bạn.

Các tệp .dll phổ biến có thể được đặt trong một thư mục con (như "\ lib" đã được đề cập ở trên) và trong các thuộc tính, hãy chọn:

  • Build Action = "HelpFiles"
  • Copy To OutputDirectory = "Nếu Mới hơn"

Điều này làm việc với tôi chính xác như mong muốn - trong quá trình xây dựng, các tệp .DLL được sao chép vào thư mục đầu ra mà không có thư mục con "\ lib".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.