Visual Studio: Como “Copiar para o diretório de saída” sem copiar a estrutura da pasta?

111

Eu tenho alguns arquivos dll na pasta \ lib da minha pasta de projeto. Na página de propriedades da dll, selecionei "Build Action" como "Content" e "Copy to Output Directory" como "Copy always".

Após a compilação, estou realmente copiando a dll, mas eles estão dentro de \ bin \ Release \ lib e não em \ bin \ Release.

Existe uma maneira de copiar arquivos dll para \ bin \ Release (e não para \ bin \ Release \ lib) sem escrever um script pós-compilação ou recorrer a nant etc?

Oh céus
fonte

Respostas:

256

em vez de <Content>usar <ContentWithTargetPath>e especificar o caminho de destino, como este:

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

Observe que essa entrada pode não estar visível no Visual Studio (2012, 2015, 2017), mas uma vez manualmente adicionada ao csproj, ela aparecerá no Visual Studio. O caminho de destino não será editável por meio da IU.

Daniel Zeitlin
fonte
2
Não vejo ContentWithTargetPath como uma opção Build Action no VS 2015. Existe uma maneira de adicioná-lo?
Kim
1
Depois de adicionar a entrada manualmente no arquivo .csproj, ela aparece como uma opção no IDE. No entanto, ainda não consigo editar o caminho de destino do IDE.
Kim
9
Minha única preocupação é que isso não será compatível com as versões futuras do MSBuild / .NET / Visual Studio / Whatever, uma vez que a interface do usuário do VS2015 não mostra essa opção ou a propriedade TargetPath.
MarioDS
1
Isso funciona para mim. Nenhuma das outras respostas funciona para mim. Esta deve ser a resposta.
GunWanderer
1
Observe que usando ContentWithTargetPathquebras de compilação incremental (testado em VS 2017 15.9.9)
Mads Ravn
26

Mantenha-os dentro $(ProjectDir)\Lib, mas adicione esses arquivos " como um link " à raiz do seu .csproj. Agora eles serão copiados para bin \ Debug (ou qualquer outra pasta de saída) sem estar em lib.

EDIT: Esta resposta foi escrita há muito tempo quando ContentWithTargetPath não estava disponível nas versões do VS / MSBuild que eu estava usando. Deixando esta resposta aqui para pessoas que podem ter que usar uma versão mais antiga do VS. Por favor, pare de comentar sobre isso, todos nós sabemos que existem maneiras melhores agora.

Ani
fonte
4
Obrigado ananthonline. Tentei seus passos, mas não ajudou. Talvez eu esteja fazendo algo errado. Aqui está o que estou fazendo, corrija se você achar que algo está incorreto: 1. Exclua essas dlls do projeto, mas deixe-as estarem disponíveis 2. Clique com o botão direito do mouse no projeto e em "Adicionar itens existentes". Selecione as dlls da lib e adicione-as "como link" 3. Clique com o botão direito nas dlls e selecione novamente "Copiar sempre" em "Copiar para diretório de saída". 4. Limpar e reconstruir. Resultado: recebi novamente essas dlls em \ bin \ release \ lib
OhDear
1
Poste uma captura de tela de sua pasta de solução após configurá-la
Ani
3
Se eu tentar adicionar um link a um arquivo que já está na árvore do projeto, ele se recusa e, em vez disso, apenas inclui o arquivo no projeto novamente ...
Nyerguds
1
Como @Nyerguds, estou percebendo que você não pode adicionar um link para um arquivo que já está na árvore do projeto, portanto, esta resposta não resolve a questão.
Tore Østergaard
1
Isso não inunda a raiz do diretório do projeto no Solution Explorer? Com muitos desses arquivos, pode ser um problema. Normalmente, a raiz de um diretório de projeto já contém muitos arquivos diversos.
Alex34758
10

Se sua intenção principal é incluir DLLs sem bagunçar o diretório raiz do projeto, outra solução é mover as DLLs para um Projeto Compartilhado separado e adicioná-lo como uma referência no projeto original.

(Observe que este post não responde diretamente a esta pergunta, pois não preserva a pasta e a estrutura do projeto, mas achei essa abordagem útil porque fui capaz de reestruturar meu projeto no meu caso e porque queria evitar alguns dos desvantagens das outras abordagens aqui.)

Passos

  • Clique com o botão direito no seu Solution -> Add -> New Project -> Shared Project
  • Adicione as DLLs a este projeto (no diretório raiz deste projeto, não em uma subpasta "lib")
  • (Verifique se as propriedades do arquivo DLL estão definidas corretamente, por exemplo, Build Action: Contente Copy to Output Directory: Copy Always)
  • Clique com o botão direito no projeto original References -> Add Reference -> Shared Projects
  • Selecione o projeto compartilhado que você criou anteriormente

A configuração é semelhante a esta:

solução-explorer-screenshot

filho
fonte
2
De longe a solução simples e elegante para manter o projeto organizado.
Ravi Ganesh,
Não consegui fazê-lo funcionar com arquivos UAP e * .bin.
Matteo
7

Adicione os arquivos dll como uma referência ao projeto e na referência defina "Copiar local" como verdadeiro.

erik_nw
fonte
1
Obrigado Erik. Isso funciona perfeitamente, exceto por uma dll que não consigo adicionar como referência. O erro que recebo ao adicionar como referência é que uma referência a 'libeay32.dll' não pôde ser adicionada. Certifique-se de que o arquivo esteja acessível e que seja um assembly ou componente COM válido.
OhDear
7
@MAnthony: Somente assemblies .NET ou assemblies de interoperabilidade COM podem ser adicionados como referências de projeto; DLLs nativas não podem ser. Você precisará encontrar outra maneira de copiar a DLL para \ bin \ Release.
Michael Liu
Obrigado Erik e Michael e ananthonline. Desculpe, não posso votar positivamente em suas respostas e comentários, pois não tenho os pontos de reputação exigidos.
OhDear
1
Para a DLL não gerenciada, você precisará usar o método que sugeri abaixo.
Ani
4

Se você precisar copiar arquivos do diretório Libs para a pasta raiz 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>

Para qualquer outra pasta, incluindo a pasta Libs (RecursiveDir)

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

Parece no VisualStudio 2015 que se as dlls que você está 'adicionando com um link' estão em uma subpasta desse mesmo projeto - elas serão automaticamente colocadas em uma pasta e a saída também será colocada em uma pasta como você viu.

Se as dlls estiverem em outro projeto ou diretório no disco que não esteja em uma subpasta do projeto , você pode 'Adicionar com um link' e elas serão colocadas no diretório raiz sem problemas.

DefenestrationDay
fonte
Mesmo no VS2012. Ele se recusa a torná-los um link e apenas os adiciona como conteúdo. No final, infelizmente, a solução mais fácil parece ser despejá-los na raiz do projeto.
Nyerguds
0

Um método alternativo é apenas deixar os itens como tipo None. No explorador de soluções, clique naqueles que deseja implantar e defina a Contentpropriedade como True.

Nota: Eu fiz isso no VS2019, e as coisas podem mudar de versão para versão.

Para fazer isso funcionar, agora clique com o botão direito em seu projeto e selecione "Descarregar projeto". Em seguida, clique com o botão direito do mouse no projeto descarregado e selecione "Editar project_name.vcxproj".

No editor, vá até o final do arquivo e insira este destino logo antes da </Project>tag final :

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

Agora, clique com o botão direito no projeto descarregado e selecione "Recarregar Projeto". Selecione para salvar e fechar se for solicitado.

Eu também defino o OutputDirectorypara:

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

e IntermediateDirectorypara:

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

na página Geral de Propriedades do Projeto. Isso coloca a saída em uma pasta "bin" e os intermediários em uma pasta "obj" na raiz de sua solução.

Nota: O $(SolutionDir)não é definido quando você executa o MSBuild a partir da linha de comando. Há um truque que você pode usar para definir isso para a pasta onde o arquivo .sln reside usando GetDirectoryNameOfFileAbove. (deixado como um exercício para o leitor). Além disso, parece que em 2019 eles estão lidando com isso corretamente na linha de comando. Sim :) O $(SolutionDir)contém uma barra invertida final, portanto, nenhuma depois dele. Os resultados de cada um devem ter uma barra invertida no final.

Agora, se você possui o Pro ou superior, não faça isso sempre que precisar criar um projeto. Isso seria coxo. Em vez disso, depois de configurar o projeto do jeito que você gosta, selecione Project -> Export Template. Você dá um nome a ele e, da próxima vez que quiser criar um projeto como aquele, basta escolher esse nome na caixa de diálogo Novo projeto. (Na versão mais antiga, acho que era Files -> Export Teamplate....)

ChuckEng
fonte
-1

Eu tive o mesmo problema com o Visual Studio 2010 / C # Project.

Para assemblies (ou seja, tendo a interface .NET), use a pasta "References" em seu projeto no Solution Explorer. Clique com o botão direito, escolha "Adicionar item existente" e localize o conjunto .dll.

Arquivos .dll comuns podem ser colocados em uma subpasta (como "\ lib" foi mencionado acima) e nas propriedades selecione:

  • Build Action = "HelpFiles"
  • Copiar para OutputDirectory = "Se mais recente"

Isso funcionou exatamente como desejado - durante a compilação, os .DLLs são copiados para o diretório de saída sem a subpasta "\ lib".

Petr Hendl
fonte