I am working on a large project that consists of multiple executables. I'd like to automate deployment process by building all of them at once. That is why I resorted to msbuild command line utility.
When I build one of my projects in Visual Studio it build normally. When I try to do the same using msbuild cmd, it fails with an error
CSC : error CS5001: Program does not contain a static 'Main' method suitable for an entry point [pathToLibrary.csproj]
This is cmd code:
msbuild MainProject.csproj -property:Configuration=Release -property:Platform="AnyCPU" -property:OutputType="WinExe" -target:"Rebuild"
pathToLibrary.csproj indeed is a library so I don't know why msbuild is trying to find a main method. There is none. It is a library.
What am I missing here?
pathToLibrary.csproj indeed is a library so I don't know why msbuild
is trying to find a main method. There is none. It is a library.
When your main project references projects by Add Reference-->Projects, it will always build not only the main projects but also the referenced projects at the same time. So when you build that project by MSBuild command lines, -property:OutputType=winexe will also apply to these referenced projects. When you build the project in VS IDE and MSBuild, you will see these info in output log.
If there is no way to instruct msbuild to only overwrite OutputType
for main .csproj, editing every file separately will have to do
If you just want to find a way to specify -property:OutputType=winexe to the main project not the referenced projects by MSBuild command line, I think there is no such function.
Or you could try my suggestions:
1) please remove -property:OutputType=winexe in MSBuild command line and when you create the related project, you have already specified the output type of the project, so you don't need to specify it in MSBuild which is not the job of the MSBuild.
Note that you can modify the property in xxx.csproj directly like <OutputType>WinExe</OutputType>.
2) if you still want this feature when you build the project with MSBuild command line, I suggest you could create a script called Directory.Build.targets which can overwrite the OutputType property and then build the project separately with MSBuild.
~a) please create a file called Directory.Build.targets in every project folder which the xxxx.csproj file exists.
~b) write the related property about the project in it:(use Exe in a console project ,use WinExe in a windows project and use Library in a class library project.)
<Project>
<Target Name="inputproperty" BeforeTargets="AssignProjectConfiguration">
<PropertyGroup>
<OutputType>WinExe</OutputType>
</PropertyGroup>
</Target>
</Project>
write like this in your MainProject project and then create another Directory.Build.targets in your pathToLibrary project to use <OutputType>Library</OutputType> so that it will meet your expectations.
Related
Summary
I am experiencing a crash in my app which I believe is ultimately caused by having two .csproj files in the same folder. I suspect this may be causing problems since the files in the obj folder do not specify which .csproj they belong to. Is it possible to have two csproj files in the same folder if they both use NuGet references? The files in the obj/ folder seem to suggest that is not a good idea.
Details
I would like to using a library (Common.Standard.csproj) on two separate projects. For reasons which would take a long time to explain, one project needs to reference an older set of nuget packages, while the other project needs newer. To solve this, I created a copy of Common.Standard.csproj which I called Common.MobileStandard.csproj. Both .csproj files are identical except that one references a different set of nuget packages.
My application crashes when I run it, and I have a missing method exception, which I believe is caused by it using the wrong .dll. I've noticed a few other symptoms which I believe are caused by the same root problem. For example, Visual Studio shows a different set of NuGet packages being referenced in the Solution Explorer vs. compared to the .csproj file:
The files shown in Visual Studio's Solution Explorer match the NuGet package references in the other .csproj which is not referenced:
I believe this may be caused by the files stored in the /obj folder. Notice that the "project" files do not specify which .csproj they belong to, so perhaps a single set of "project" files is created despite there being two .csproj files outside of the obj folder?
Am I correct in assuming that this is causing the confusion in Visual Studio, and also the missing method exception at runtime? If so, does that mean that two .csproj files should never share the same folder?
Update 1
I followed suggestions below to use a different in the Common.MobileStandard.csproj so that each .csproj would have its own obj folder, as shown here:
This did produce an objmobile file as expected:
However, the objmobile folder remains empty wnen I build the Common.MobileStandard project. Furthermore, if I delete the contents of the obj folder (the non-mobile one), the nuget packages in Visual Studio get cleared out. It seems as if Visual Studio is always looking in the obj folder rather than in the objmobile, even though the .csproj tells it to look in the objmobile, as shown in the following animation:
I believe the only solution here is to move the .csproj to a separate folder unless I'm mistaken in this being a Visual Studio (or msbuild) bug.
Update 2
It seems that the issue listed in Update 1 is expected behavior. After changing , the following is shown in the output when building the project:
3>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(858,5): warning MSB3539: The value of the property "BaseIntermediateOutputPath" was modified after it was used by MSBuild which can lead to unexpected build results. Tools such as NuGet will write outputs to the path specified by the "MSBuildProjectExtensionsPath" instead. To set this property, you must do so before Microsoft.Common.props is imported, for example by using Directory.Build.props. For more information, please visit https://go.microsoft.com/fwlink/?linkid=869650
To fix this, I can create a new file named Directory.Build.props with the following contents:
<Project>
<PropertyGroup>
<MSBuildProjectExtensionsPath>objmobile</MSBuildProjectExtensionsPath>
</PropertyGroup>
</Project>
This does solve the issue in Update 1 (why nuget is still reading from obj) but it brings up a second question - how can I have a different Directory.Build.props for each .csproj file?
It seems I can set BaseIntermediateOutputPath in the .csproj file if I structure it like this:
<Project>
<PropertyGroup>
<BaseOutputPath>bin-example</BaseOutputPath>
<BaseIntermediateOutputPath>obj-example\</BaseIntermediateOutputPath>
<RestorePackagesPath>packages-example\</RestorePackagesPath>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk"/>
<!-- stuff VS normally puts in <Project> -->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk"/>
</Project>
That is, I pulled the Sdk attribute out of the Project tag and converted it to imports, so that I could set things before importing Sdk.props.
I did that based on the page here: https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2022
In a test rebuild which makes use of nuget packages, this does not touch the obj folder.
It seems .NET Framework projects are structured differently, and I don't think this approach will work there. Hopefully you don't need more than one Framework project in the same directory.
I am trying to include Directory.build.props file as I want to have one place to change the version of all the projects.
If I build solution using Visual Studio the properties inside Director.build.props file are correctly embedded inside the built exe file.
If I use the dotnet build command, the exe file does not have the required properties embedded.What I observed is that the dll files have correct properties embedded using CLI command as well using Visual Studio.
The Directory.build.props file is located at the root of the solution (I've tried putting it at the root of the project and the same thing happens).
This is the Directory.build.props file that I'm using
<Project>
<PropertyGroup>
<Company>Company</Company>
<Copyright>Copyright</Copyright>
<Version>1.0.0</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<FileVersion>1.0.0</FileVersion>
</PropertyGroup>
</Project>
I'm wondering if I'm missing some configuration, and why are dlls successfully embedded with properties while the exe file is not?
Credits go to #Martin Ullrich, but on *nix the file should indeed be called Directory.Build.props (proper casing) otherwise it will be ignored.
Setting the attributes on the apphost executable is supported in the 3.0 SDK. Make sure you have at least the 3.0.100 SDK (i tested .NET Core 3.0 Preview 5) installed.
I have a solution with 2 projects. One is a VSIX and the other is a .NET Core 2.1 Console app.
The projects do not directly depend on each other, but I need to ensure that VSIX embeds a fresh version of all output files from the other project as it is built, because it will need them at runtime.
Putting the following in the post-build event of the VSIX project used to work:
cd "$(SolutionDir)MyCoreConsoleApp"
dotnet publish --configuration $(Configuration)
It's worth mentioning that there were some strange problems with this setup in the beginning, though... The console app could be built fine if done by issuing rebuild of the project from Solution Explorer directly. Issuing dotnet publish from VSIX's before-build, on the other hand, would fail with errors, basically saying the build system could not locate all the required files.
After a lot of effort, I determined that the problem was the fact that console app used Fody Costura at the time. After removing this dependency, dotnet publish started working without any problems.
Fast forward to yesterday... I added a dependency on MSBuild Community Tasks to console app project, because I wanted to use the Zip task to embed a zipped copy of some content files as EmbeddedResource. I've added a custom Target to the csproj and confirmed that it worked correctly when doing a direct build of the project or issuing dotnet publish from command line. In case it matters, the Target itself looks like this:
<Target Name="ZipAndEmbedWwwRoot" BeforeTargets="BeforeBuild">
<CreateItem Include="wwwroot\**\*">
<Output ItemName="ZipFiles" TaskParameter="Include" />
</CreateItem>
<Zip ZipFileName="$(IntermediateOutputPath)wwwroot.zip" WorkingDirectory="wwwroot" Files="#(ZipFiles)" />
<ItemGroup>
<EmbeddedResource Include="$(IntermediateOutputPath)wwwroot.zip">
<LogicalName>wwwroot.zip</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Target>
But now building the VSIX started failing again. The error is:
The "MSBuild.Community.Tasks.Zip" task could not be loaded from the
assembly
C:\Users\MyUserName\.nuget\packages\msbuildtasks\1.5.0.235\build\..\tools\MSBuild.Community.Tasks.dll.
Could not load file or assembly 'Microsoft.Build.Utilities.v4.0,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
The system cannot find the file specified. Confirm that the
declaration is correct, that the assembly and all its
dependencies are available, and that the task contains a public class
that implements Microsoft.Build.Framework.ITask.
As soon as I remove the custom Target, things start working again.
I'm starting to think I'm probably missing something when calling dotnet publish on a project, which has additional msbuild dependencies. This was probably the reason why Fody Costura didn't work, either.
So the question is, how should I be doing this, then?
The community Zip task is quite old and no longer works with recent versions of MSBuild or the cross-platform dotnet CLI.
However, VS 2017 15.8 and the CLI 2.1.400 introduced the built-in ZipDirectory task you could use instead.
I'm completely new to WiX and setting up custom installers in general, so I apologise for the topic of the question!
I have a internal business application (a diary), which builds and works well, so I followed tutorials/official documentation as to adding the WiX project and referencing the Diary's csproj to it.
After then building and running this most basic version of a WiX installer, the output directory has a lone exe file, which crashes moments after loading with a File Not Found Exception.
My guess is that it has not built in either Crystal Report or NLog, both of which are referenced in my CSProj.
My question is this, how do I get WIX to include and build those project references to the output???
Any help is greatly appreciated!
/Antony
Unfortunately you will have to do some manual labor in order to get your projects right. I would take either of the two following approaches which require you to edit the .wixproj file:
Use HeatProject task. You will have to do this for all referenced projects and it will give you separate .wxs files for all of them. After this reference the component groups in those files in a feature of your WIX based setup.
<Target Name="BeforeBuild">
<HeatProject ToolPath="$(WixToolPath)" AutogenerateGuids="true" OutputFile="OutputFile.wxs" SuppressFragments="true" Project="ReferencedProject.csproj" ProjectOutputGroups="Binaries" />
</Target>
Use HeatDirectory task. Following will pick up everything in the bin folder of your project, including any binaries for the referenced projects, and give you a single .wxs containing UniqueComponentGroupName which can be included in any feature.
<Target Name="BeforeBuild">
<PropertyGroup>
<DefineConstants>BINFOLDER=PATH\TO\YourProject\bin\$(Configuration)</DefineConstants>
</PropertyGroup>
<HeatDirectory OutputFile="OutputFile.wxs" Directory="PATH\TO\YourProject\bin\$(Configuration)" KeepEmptyDirectories="true" DirectoryRefId="INSTALLFOLDER" ComponentGroupName="UniqueComponentGroupName" SuppressCom="true" SuppressFragments="true" SuppressRegistry="true" SuppressRootDirectory="true" GenerateGuidsNow="true" ToolPath="$(WixToolPath)" PreprocessorVariable="var.BINFOLDER" />
</Target>
Unlike the (now defunct) Setup Project project in older versions of Visual Studio, WiX does not do automatic reference detection. You'll have to add each referenced project to the WiX project manually, just as you did for the main project.
For a visual C# project in microsoft visual studio IDE, what is the configuration settings to be used, so that it could generate both exe and dll outputs?
What you want can be easily achieved using nant. You have to create a simple xml file that is the script and that can be easily executed through a batch file. Once you created them then it's very easy no more manual work, every time when you need to build the project all you have to do is just execute the script.
Here is an excellent tutorial about nant.
As Darin points out in comments, there is no setting to do this. However, you can achieve it via build events and batch scripts
Create a pre-build event on the dll project to call a batch script
In the batch, copy the csproj for the dll project
Modify the XML content of the copied csproj to change the output type to exe
Modify the output directory of the copied csproj
Run this in Visual Studio
You will now get a copy of your csproj generated which outputs to exe. You can add the second csproj into visual studio and every time you build, it should synchronize the exe csproj and build it.
Some tips:
You can modify csproj's using Powershell. See here
You may want to modify all cs files in the copied csproj to be links
I know this is an old question but it is possible to do a lot of things in the proj-files that is not possible in the user interface.
For this specific issue you just do like this:
Create a new project configuration, e.g. ReleaseExe
In the project's csprojfile you will find the following line
<OutputType>Library</OutputType>
After that line add the following line
<OutputType Condition="'$(Configuration)|$(Platform)' == 'ReleaseExe|AnyCPU'">Exe</OutputType>
Save, open the project and use batch build to build both the dll and exe
The nice thing is that you can use the Condition attibute on all tags in the project file. I have a project where I need to create two versions based on different 3rd party assemblies. To solve that I just add a condition to the reference tag.
<Reference Include="3rdParty" Condition="'$(Configuration)|$(Platform)' == 'Release1|AnyCPU'">
<HintPath>Release1\3rdParty.dll</HintPath>
</Reference>
<Reference Include="3rdParty" Condition="'$(Configuration)|$(Platform)' == 'Release2|AnyCPU'">
<HintPath>Release2\3rdParty.dll</HintPath>
</Reference>