web-dev-qa-db-fra.com

MSBuild - Les cibles spécifiques à un projet pour la solution ne fonctionnent pas

J'ai une solution qui contient plusieurs projets, y compris une application Web. Je souhaite que MSBuild exécute la cible "WebPublish" sur le projet d'application Web et la "cible par défaut" pour tous les autres projets de la solution.

Cet article MSDN indique que je peux le faire en spécifiant la ligne de commande

msbuild SlnFolders.sln /t:NotInSlnfolder:Rebuild;NewFolder\InSolutionFolder:Clean

Mais je n'ai jamais pu le faire fonctionner - MSBuild a renvoyé une erreur, quelque chose comme "NotInSlnFolder: Rebuild", la cible n'existe pas. Quelle que soit la cible à spécifier, Construire, Reconstruire ou Nettoyer, cela ne fonctionne en aucun cas.

Comment puis-je atteindre mon objectif de spécification d'objectifs spécifiques à un projet pour une solution?

La documentation MSDN ne fonctionne pas. Ou ai-je raté quelque chose?

23
Philipp Munin

REMARQUE: cette solution de contournement n'est pas officiellement prise en charge par Microsoft. Par conséquent, rien ne garantit qu'il fonctionnera pour toujours.


Réponse courte

Dans le dossier contenant le fichier SLN, créez le fichier before.{YourSolution}.sln.targets, avec le contenu suivant: (Remplacez ce qui est entre accolades comme vous le souhaitez.)

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.Microsoft.com/developer/msbuild/2003">
  <Target Name="{MyCompany_MyProduct_WebApp:WebPublish}">
    <MSBuild
        Condition="'%(ProjectReference.Identity)' == '{$(SolutionDir)MyCompany.MyProduct.WebApp\MyCompany.MyProduct.WebApp.csproj}'"
        Projects="@(ProjectReference)"
        Targets="{WebPublish}"
        BuildInParallel="True"
        ToolsVersion="4.0"
        Properties="BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)"
        SkipNonexistentProjects="%(ProjectReference.SkipNonexistentProjects)" />
  </Target>
</Project>

Après cela, vous pouvez exécuter la ligne de commande:

msbuild {YourSolution}.sln /t:{MyCompany_MyProduct_WebApp:WebPublish}

Longue réponse

Si vous ajoutez variable d'environnement MSBUILDEMITSOLUTION en définissant sa valeur sur 1, MSBuild ne supprimera pas les fichiers temporaires générés pour la solution et les projets.

Cela vous permettra de rechercher les fichiers {YourSolution}.sln.metaproj et {YourSolution}.sln.metaproj.tmp générés dans le dossier de la solution, qui ne sont que des fichiers de projet MSBuild standard.

Pour MSBuild 3.5 , le fichier généré est {YourSolution}.sln.cache et est conservé quelles que soient les variables d'environnement. En analysant ces fichiers, vous comprendrez les détails de bas niveau du processus et pourrez voir les opportunités de personnalisation disponibles.

Après avoir exécuté MSBuild avec une cible spécifique au projet dans le fichier .Metaproj, vous constaterez que la liste des cibles spécifiques au projet est codée en dur et seules les cibles standard sont prises en charge (Build, Rebuild, Clean, Compile , Publier; remarque: Publier et WebPublish ne sont pas identiques). MSBuild 3.5 ne génère que des cibles de nettoyage, de reconstruction et de publication, ainsi que une cible portant uniquement le nom du projet, qui signifie "Construire".

Vous pouvez également voir que NotInSlnfolder:Rebuild est juste le nom d'une cible générée automatiquement . En réalité, MSBuild ne l’analyse pas et ne se soucie pas des noms et de l’emplacement des projets. Notez également que les noms de cible générés automatiquement spécifient le nom du projet avec la hiérarchie des dossiers de solutions s’il en est un, par exemple. SolFolder\SolSubfolder\ProjectName:Publish.

Une dernière chose d’importante est le nom de la cible MSBuild ne prend pas en charge les points . Tous les points des noms de projets sont remplacés par des traits de soulignement . Par exemple, pour un projet nommé MyCompany.MyProduct.Components, vous devrez spécifier dans la ligne de commande:

/t:MyCompany_MyProduct_Components:Rebuild

C'est pourquoi même la construction cible cible spécifique au projet standard ne fonctionnait pas - mon nom de projet contenait dots .

En analysant le fichier {YourSolution}.sln.metaproj.tmp, vous découvrirez qu’au moment de l’exécution, le système tente d’importer des cibles à partir du fichier nommé before.{YourSolution}.sln.targets et after.{YourSolution}.sln.targets, si ces fichiers existent. Cela a une clé pour la solution de contournement pour cette limitation/bogue MSBuild.

39
Philipp Munin

Vous pouvez ouvrir votre fichier de solution dans l’éditeur de texte et vérifier si la ligne suivante existe ou non. Sinon, vous pouvez ajouter

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> dans la balise <Project>.

J'espère que cela vous aidera.

1
imdadhusen