Is it possible to specify the target platform (x64, x86) when building a project?
I have a build task that looks as follows:
<MSBuild Projects="%(AgentProjectFiles.FullPath)" Properties="Architecture=x86;Configuration=$(Configuration);Optimize=$(Optimize);Platform=$(Platform);OutputPath=$(OutputDirectory)\Agent\;ReferencePath=$(ReferencePath);DebugSymbols=$(DebugSymbols);DebugType=none;" />
As you can probably tell, I've thrown everything possible I have seen online into the Properties attribute in the hope that it will work. You will notice that for the Architecture property I've set it to be x86 explicitly. the $(Platform) is also set to x86. I've tried a number of permutations, without success.
Unfortunately, it seems that no matter what gets put into these properties, my class libraries are x86, but my executables are x64.
I thought perhaps the problem could be that the build properties specified in the project file itself were causing MSBuild to ignore the ones I pass through from MSBuild, but after changing these to x86, I still have the same problem.
Any ideas?
In the declaration of the AgentProjectFiles item are you defining the Properties metadata. So does it look like:
<ItemGroup>
<AgentProjectFiles Include="something.proj">
<Properties>SOME VALUES HERE</Properties>
</AgentProjectFiles>
</ItemGroup>
If you have defined that then the properties passed into the Properties attribute of the MSBuild task are ignored. I've bloged about this MSBuild: Properties and AdditionalProperties Known Metadata.
Sayed Ibrahim Hashimi
My Book: Inside the Microsoft Build Engine : Using MSBuild and Team Foundation Build
Related
I'm trying to understand what some of the best practices are when using modern CMake (3.13+) with respect to building and including vendored or submoduled code.
Say I'm building a library MyLib. My file structure is something like this
MyLib
|-CMakeLists.txt
|-src
|-include
|-submodules
|-libgeos
In this example, I've included libgeos as a git submodule, because it's really convenient to be able to clone the project and immediately build and run tests because that dependency is present. This could also be solved by using FetchContent or something, and my question still stands; the important thing is that I do not want to rely on libgeos being installed in build environment.
Note I picked libgeos arbitrarily; I have no idea if libgeos is set up as a cmake project appropriately for this example, but this is all theoretical and I just needed some concrete library name. Please do not use the specific details of how libgeos is configured to answer this, unless libgeos is a good example of conventional cmake.
But now, there's some other project that wants to use my project, and it needs libgeos and doesn't want to depend on my project providing it.
OtherProject
|-CMakeLists.txt
|-src
|-include
|-submodules
|-libgeos
|-MyLib
|submodules
|-libgeos
When you clone OtherProject, you get two versions of libgeos, and maybe that's not great; but it's not a huge issue either. And maybe they're not the same version; say MyLib requires libgeos >= 2.0, so 2.0 is what MyLib includes, and OtherProject requires libgeos>=2.1 so OtherProject includes libgeos >= 2.1.
Now we potentially end up with some build issues. If we have the following line in OtherProject/CMakeLists.txt
add_subdirectory(submodules/libgeos)
and then again, that same line within MyLib/CMakeLists.txt, we end up with cmake errors because libgeos as a target is defined twice in the build. This can be solved a couple of ways.
Check if geos exists before adding it
if(NOT TARGET geos)
add_subdirectory(submodules/libgeos)
endif()
But this case has some issues; if that blob is in OtherProject at the top, it's fine and both projects use libgeos 2.1. But if it's in OtherProject after add_subdirectory(submodules/MyLib), then the geos 2.0 version gets added to the build, which may or may not fail loudly (Hopefully it would).
This could also be solved with find_package. Both projects include cmake/FindGeos.cmake which use that blurb above (if(NOT TARGET...)) to add geos the build and then the top project cmake files can do this
list(APPEND CMAKE_MODULE_PATH cmake)
find_package(geos 2) # (or 2.1)
then it doesn't matter what order they try to include geos, because they will both defer to FindGeos.cmake in OtherProject because it's first in the module path.
But now there's a new issue, some ThirdProject wants to use MyLib also, but ThirdProject wants to depend on libgeos which is in the system environment. It uses find_package(geos 2.1 CONFIG) to use the installed GeosConfig.cmake file, which adds geos::geos to the build and sets geos_FOUND. Suddenly, MyLib fails to build, because geos_FOUND was set, but I'm doing target_link_library(mylib PUBLIC geos).
So this could be solved by adding add_library(geos::geos ALIAS geos) in both custom FindGeos.cmake files, then it doesn't matter if geos was built from source or using the installed version, the target names are the same either way.
Now we get to my actual questions:
Lets start with
Am I crazy, no one does this, and my team is trying to use cmake all wrong?
Is there some feature of cmake that I've just completely missed that solves all these problems?
I suspect there's a good few books or presentations that cover this topic, but I just don't know where to look because there's so many; what should I be looking at? I've seen the CMake Packages page, which looks like it solves the problem when you're using all projects which are configured according to that page; but it doesn't really answer how to bridge the gap between older and newer projects.
If I'm not crazy and there's no straightforward answer or presentation that I can look at, then
What should the cmake configuration for both MyLib and libgeos look like so that these cases work?
MyLib is built alone
MyLib is built as part of a larger project which provides a different version of geos
MyLib is built as part of a larger project which depends on a different version of geos in the environment
I understand that cmake provides helpers that could be used to produce MyLibConfig.cmake if I wanted to install it in the environment. I also see that the export() function exists, which could be used to save those files in the build tree somewhere and then find them with find_package in config mode. But this feels a bit odd to me to do because it's not a multi-stage build, it's just one invocation of cmake then make.
But lets say that's the right answer and the CMake for libgeos doesn't follow it. Would it be appropriate to have FindGeos.cmake do something like this?
if(NOT geos_FOUND)
add_subdirectory(submodules/libgeos)
export(geos NAMESPACE geos)
find_package(geos CONFIG)
endif()
I don't need ALL_BUILD subproject, can I avoid generating it? Thanx.
CMake Issue #16979: "ALL_BUILD target being generated":
The ALL_BUILD target corresponds to CMake's notion of the "all" target, equivalent to make all with makefile generators. This is different from "Build Solution" behavior due to idiosyncrasies in how the VS IDE deals with inter-vcxproj dependencies.
There is no way to suppress the ALL_BUILD target. It must exist for commands like cmake --build. to be able to build the "all" target by default.
So you can't avoid it - as with #arrowd answer - but there are some things in CMake that can influence the usage/appearance (on IDE generators like Visual Studio) of it:
When you activate global USE_FOLDERS property
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
the generic targets ALL_BUILD, ZERO_CHECK, INSTALL, PACKAGE and RUN_TESTS will be grouped into the CMakePredefinedTargets folder (or whichever name is given in global PREDEFINED_TARGETS_FOLDER property).
The global variables CMAKE_SKIP_INSTALL_ALL_DEPENDENCY and CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY do suppress otherwise automatically generated dependencies for INSTALL or PACKAGE to the ALL_BUILD target.
The global VS_STARTUP_PROJECT property can be used to change the default startup project name to something other than the ALL_BUILD or "first project not in sub-folder" targets.
References
What are ALL_BUILD and ZERO_CHECK and do I need them?
How to skip dependency on all for package target?
No CMakePredefinedTargets when using solution folders
It corresponds to the all make target, so, no, you can't avoid generating it. You can delete it from the solution manually, though.
I have a project with the following structure:
project_name/CMakeLists.txt
project_name/src
project_name/resources
...
project_name-build/configuration_name/project_name.exe
I want my application to be run in the root project directory project_name so it can directly access resources.
Does CMake provide a method to specify this property, or will I have to manually set it in each build environment I use?
I've looked around in the documentation and haven't found anything other than the possibility of setting up a post-build event to run my project from the desired directory which is less than desirable. I also found that the working directory setting for Visual Studio is saved in a per-user file (.vcxproj.user) which I don't believe CMake generates (which points to the answer being probably no).
Since CMake 3.8, there is the VS_DEBUGGER_WORKING_DIRECTORY target property, which allows you to set the debugger working directory for a target in Visual Studio.
Usage example:
set_property(TARGET MyTarget PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
As drescherjm pointed out (in his comment on the question) CMake doesn't provide a method to directly set a working directory. However, CMake does provide indirect methods of doing so.
The path I think I'll take is to use the configure_file command to fill in a template .user file.
Here is an easier solution.
Paste this at the end of your cmake:
file( WRITE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.vcxproj.user"
"<?xml version=\"1.0\" encoding=\"utf-8\"?> \
<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>")
It overwrites the default vcxproj.user file for the current project and specifies $(OutDir) for the Working Directory as desired for debugging. Make sure that $PROJECT_NAME is your project name.
I'm using MSbuild class for compile visual studio 2010 projects from module of my programm.
But I can't find how to tell compiler which optimization flags it must use.
There is only Optimize property on MSBuild and only tag at .vcxproj file. But I want to play with such compiler switch like /Os /Ot /Oi etc. How to do that?
There is standard CL Task in MSBuild, which is represented by
<ClCompile>
tag in .vcxproj file. So it's possible to playing with compiler switches via Parameters of this task
I have a MSBuild .proj file that is compiling a mixture of C# and C++ projects.
The C# projects compile output (.exe/.dlls) to the OutputPath I specify, but when I specify OutputPath for the C++ projects (which calls vcbuild.exe), the OutputPath is ignored and instead goes into the directory specified in the Property Pages for the .vcproj.
Here's my MSBuild task:
<MSBuild Projects="$(SourceFolder)\$(NativeSolutionName)"
Targets="$(BuildTargets)"
Properties="Configuration=$(Configuration);PlatformName=Win32;OutputPath=$(ToolsOutputDir)">
</MSBuild>
How can I specify that the C++ output files should go to the same directory as the C# output files $(ToolsOutputDir)?
I was able to make this work by doing the following:
1) Installing the Microsoft SDC MSBuild Tasks Library
2) In the property pages for the C++ projects, setting the output directory to $(OutputPath).
3) Adding a SDC task to set the environment variable OutputPath before building the C++ projects via VCBuild:
<Microsoft.Sdc.Tasks.SetEnvironmentVariable Variable="OutputPath" Value="$(ToolsOutputDir)" Target="Process"/>
<!-- Build any CPP code x86 -->
<MSBuild Projects="$(SourceFolder)\$(NativeSolutionName)"
Targets="$(BuildTargets)"
Properties="Configuration=$(Configuration);PlatformName=Win32;OutputPath=$(ToolsOutputDir)">
</MSBuild>