I'm currently attempting to build a C++ library and what I would like is that every time the build button is pressed I would get all of the include files to be moved to a certain directory.
What I currently have is this
<Target Name="CopyToIncludeFiles">
<Message Text="Copying All '*.h' and '*.hpp' to the include directory" Importance="high">
</Message>
<Copy SourceFiles="#(ClInclude)" DestinationFolder="..\HelperLib\x86\include\">
</Copy>
</Target>
And I include the target in the DefaultTargets likes so
<Project ToolsVersion="4.0" DefaultTargets="Build;CopyToIncludeFiles;" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
This all works fine so long as I use the rebuild, yet this never runs when I just hit build.
What do I need to do to have this run whether I hit build or rebuild?
I think task you solving easier to do with PreBuild Event in project properties, as it is just simple command-line command.
If you still want msbuild - you may use BeforeTargets like this:
<Target Name="CopyToIncludeFiles" BeforeTargets="Rebuild;Build">
<Message Text="Copying All '*.h' and '*.hpp' to the include directory" Importance="high" />
<Copy SourceFiles="#(ClInclude)" DestinationFolder="..\HelperLib\x86\include\" />
</Target>
You should not change project DefaultTargets property to include your task.
Also notice that both PreBuild event and this msbuild task will not run in case your project code doesn't require recompilation (i.e. no cpp / h files changed).
Related
I have a pubxml that is used in the VSBuild#1 task and the build works fine except I dont get my .pdb files. How can I make sure the .pdb files are also included in my release?
Project release Config
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Staging2|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>default</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
Pubxml file
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>FileSystem</WebPublishMethod>
<PublishProvider>FileSystem</PublishProvider>
<LastUsedBuildConfiguration>Staging2</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>False</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<publishUrl>Publish</publishUrl>
<DeleteExistingFiles>True</DeleteExistingFiles>
<TargetFramework>net472</TargetFramework>
<DebugSymbols>True</DebugSymbols>
<DebugType>Full</DebugType>
</PropertyGroup>
</Project>
YAML build task
task: VSBuild#1
inputs:
solution: '**\MyApps\Main.csproj'
msbuildArgs: '/t:build /p:DeployOnBuild=true /p:PublishProfile=publish.pubxml /p:OutputPath=$(build.artifactStagingDirectory)\MainPublish\'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
Based on what I have looked up, if you can set the /Build=full property it will be fine. Well my question is if thats the case, where do I add it?
The MSBuild arguments equivalent of the <DebugType>Full</DebugType> part of the project file is: /p:DebugType=full.
So, if you change your msbuildArgs section of the VSBuild task by adding /p:DebugType=full, this should do the trick.
Above All
To save your time from reading a lot, Thanks to CristiFati and here is the answer:
If you use "Library" in "ConfigurationType" like me, you'll get an .obj file instead of .dll.
The right keyword is "DynamicLibrary" instead of "Library". That is:
<ConfigurationType>DynamicLibrary</ConfigurationType>
Then you'll have the .dll you want.
[supplement] From CMake Documents, thanks to Botje's guiding, it appears that a "Library" is actually like a sub-directory under the root project. Thus it's different with how dll work.
Short Story:
I need to compile a dll with MSbuild, without any IDE.
I followed instruction on Microsoft Doc to create app build project.
No webpage indicates how to create dll build project is found yet. Thus I edit .vcxproj according to similar google info.
BUILD SUCCESS!
But the result only contain a .obj file. No dll in sight.
Need help about how to modify a .vcxproj to build a dll.
Detailed Story:
I need to compile a dll.
My company didn't buy any commercial license thus I cannot use any IDE for this.
However MSBuild is safe to use.
I'm following this page to create a C++ project which could be compiled with MSBuild only.
https://learn.microsoft.com/en-us/cpp/build/walkthrough-using-msbuild-to-create-a-visual-cpp-project?view=vs-2017
You don't need actually read that page because I'll paste the project file below.
First, Following that page, I got this application type project file
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.default.props" />
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ItemGroup>
<ClCompile Include="helloworld.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="helloworld.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Targets" />
</Project>
I tested the build. And got my .exe file successfully. And my helloworld.exe printed "HelloWorld" as predicted. Then...
Second, Following this page:
https://learn.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=vs-2017
I'm sure the header and cpp file is good to go
#pragma once
#ifdef HELLOWORLD_EXPORTS
#define HELLOWORLD_API __declspec(dllexport)
#else
#define HELLOWORLD_API __declspec(dllimport)
#endif
extern "C" HELLOWORLD_API void helloworld();
Third, Switch this project from application mode to library mode...
Actually I'm not sure how to do this. So I googled some info and try to do what they did.
I change the Debug mode to Release mode.
Then change the Application output to Library.
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.default.props" />
<PropertyGroup>
<ConfigurationType>Library</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ItemGroup>
<ClCompile Include="helloworld.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="helloworld.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Targets" />
</Project>
Finally, I let msbuild do its work:
msbuild helloworld.vcxproj /p:configuration=Release
And the build is success!
But when I head to Release folder under my root directory, I find only a "helloworld.obj" file and a "vc141.pdb" along a folder names "helloworld.tlog".
Well this is not right. I think the right result will be a "helloworld.dll" in here.
So, that should be my .vcxproj file's problem I guess.
So, could anybody kindly give a guide for creating a dll project from scratch?
Thanks!
Although using the IDE is prohibited by licensing purposes, listing [MS.Docs]: Walkthrough: Create and use your own Dynamic Link Library (C++) anyway.
The keypoint is:
3. From the filtered list of project types, select Dynamic-link Library (DLL), and then choose Next.
Behind the scenes, that maps to: [MS.Docs]: ConfigurationTypes Enum:
Fields
typeApplication 1 Application (.exe)
typeDynamicLibrary 2 Dynamic Library (.dll)
typeGeneric 10 Makefile, displays makefile toolset (NMake)
typeStaticLibrary 4 Static Library (.dll)
typeUnknown 0 Utility
Translated to .vcxproj structure, the ConfigurationType node:
<ConfigurationType>Application</ConfigurationType>
should be converted to:
<ConfigurationType>DynamicLibrary</ConfigurationType>
But, as (#Botje's) comments rightly pointed out, you should move towards free build tools (there are a number of alternatives, and CMake seems to be the best one).
In order to keep the repository clean and separated from output and build files we change corresponding paths in the project file.
For Net Framework project specifying IntermediateOutputPath redirects the obj directory to the corresponding folder.
For Net Core project (3.0) using this property is not sufficient. Whereas Debug, Release folders are indeed redirected, the obj folder is still created and it contains some file - such as
project.assets.json, .csproj.nuget.cache, .csproj.nuget.dgspec.json,.csproj.nuget.g.props, .csproj.nuget.g.targets .
Using BaseIntermediateOutputPath - doesnt help either.
Just wonder if someone can suggest how to move the whole obj directory?
Thanks
The Solution suggested by Martin works fine for Net Core projects
<Project>
<PropertyGroup>
<BuildDIrectory>C:\Temp\Build\$(Configuration)</BuildDIrectory>
<RelativePath>some arelative path which depends on location of corresponding project withing the solution</RelativePath>
<BaseIntermediateOutputPath>$(BuildDIrectory)\obj\$(RelativePath)\$(AssemblyName)\</BaseIntermediateOutputPath>
<OutputPath>$(BuildDIrectory)\out\$(RelativePath)\$(AssemblyName)\</OutputPath>
<DocumentationFile>$(BuildDIrectory)\Documentation\$(RelativePath)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
...
</Project>
BaseIntermediateOutputPath works as well, but it needs to be set very early in order to take effect.
The easiest way would be to add it to a Directory.Build.props file:
<Project>
<PropertyGroup>
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory)..\shared-obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
</PropertyGroup>
</Project>
If you want to specify it directly in the csproj file, you cannot use the <Project Sdk=" notation since the property needs to be set before parts of the SDK are applied. However it works when using explicit SDK imports and correct ordering:
<Project>
<PropertyGroup>
<BaseIntermediateOutputPath>..\shared-obj\myprojA\</BaseIntermediateOutputPath>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>
In my C++ VS project I added a custom target to compile shader files and set it as a initial target. This is the project xml
<Project InitialTargets="CompileShaders" DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
..... Normal Default VS C++ content here ......
<ItemGroup>
<GLSLShader Include="SPIR-V\canvas2D.vert" />
<GLSLShader Include="SPIR-V\canvas2D.frag" />
</ItemGroup>
<Target Name="CompileShaders" Inputs="#(GLSLShader)" Outputs="SPIR-V\shaders_bytecode.h" >
<PropertyGroup>
<OriginalFileName>%(GLSLShader.Filename)%(GLSLShader.Extension)</OriginalFileName>
</PropertyGroup>
<Message Text="Start Compiling GSLANG #(GLSLShader) " />
<Message Condition="'$(VULKAN_SDK)'==''" Text="Error, cant find environment variable VULKAN_SDK, Make sure that the Lunar Vulkan SDK is installed" />
<Message Condition="'$(VULKAN_SDK)'!=''" Text="$(VULKAN_SDK)\Bin\glslangValidator.exe %(GLSLShader.Filename)%(GLSLShader.Extension) -V --vn $([System.String]::Copy('%(GLSLShader.Filename)%(GLSLShader.Extension)').Replace('.','_')) -o %(GLSLShader.Filename)%(GLSLShader.Extension).h" />
<Exec Condition="'$(VULKAN_SDK)'!=''" Command="$(VULKAN_SDK)\Bin\glslangValidator.exe %(GLSLShader.Filename)%(GLSLShader.Extension) -V --vn $([System.String]::Copy('%(GLSLShader.Filename)%(GLSLShader.Extension)').Replace('.','_')) -o %(GLSLShader.Filename)%(GLSLShader.Extension).h" WorkingDirectory="$(ProjectDir)\SPIR-V" />
<Exec Condition="'$(VULKAN_SDK)'!=''" Command="del shaders_bytecode.h" WorkingDirectory="$(ProjectDir)\SPIR-V" />
<Exec Condition="'$(VULKAN_SDK)'!=''" Command="type %(GLSLShader.Filename)%(GLSLShader.Extension).h >> shaders_bytecode.h" WorkingDirectory="$(ProjectDir)\SPIR-V" />
<Exec Condition="'$(VULKAN_SDK)'!=''" Command="del %(GLSLShader.Filename)%(GLSLShader.Extension).h" WorkingDirectory="$(ProjectDir)\SPIR-V" />
</Target>
</Project>
if I change any .cpp .h file and build the solution, the shaders are compiled together with the rest of the project, but if I change only the shader files (i.e SPIR-V\canvas2D.vert) the project is not built. VS says that the project is up to date.
Now the strange thing, If I run the project using msbuild on the terminal ouside VS, the shader files changes are enough to trigger the rebuild. Go figure....!!!
It looks like something related to how VS build projects. It is outside the msbuild.
Aha!! Found it in this article. It turns out visual studio bypass msbuild and uses some other criteria to verify if a project is up to date or not. If the criteria fails it then runs the msbuild on that project.
To override the visual studio behavior set the property DisableFastUpToDateCheck as true in the Globals property group of your project's xml:
<PropertyGroup Label="Globals">
<!-- Other Global Property Settings -->
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
</PropertyGroup>
And it is done... I wonder if there is a away to tell Visual Studio FastUpToDateCheck Mechanism to also pay attention to the custom build files ????? The solution above will suffice for now.
I have the following targets:
<Target Name="Build" DependsOnTargets="Build_Shared" />
<Target Name="Build_Shared" DependsOnTargets="Build_Shared_x86;Build_Shared_x64"/>
<Target Name="Build_Shared_x86" DependsOnTargets="SetPlatform_x86;Shared_1;..." />
<Target Name="Build_Shared_x64" DependsOnTargets="SetPlatform_x64;Shared_1;..." />
The problem is that Shared_1 dependency is not build in the x64 target. I guess MSBuild thinks that it is already build due to the x86 target. I don't want to create different x86/x64 targets for all my shared components. And i have applications (depending on Build_Shared) that require x86 and x64 to build so i need a dependency like this.
Note that each target is only executed once during the build. If you have multiple targets depending on your Shared_1 target, Shared_1 will only be run once, and will considered to already be run when a second DependsOnTargets="..;Shared_1;.." is encountered.
If you need to run the same target multiple times, you need to use a nested msbuild command:
<Target Name="Build_Shared">
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Shard_1" Properties="Platform=x86" />
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Shard_1" Properties="Platform=x64" />
</Target>
You could also use Targets="SetPlatform_x86;Shared_1;.." if you need that.