Adding data files to cmake-generated projects - visual-studio-2010

I have a project where the source files are in source/ and some shader files in data/ (those are not compiled, but instead loaded by the code). I'd like these files to show up in my CMake-generated VS2010 project files so I can edit them comfortably. What's a good way to do this? Ideally, they'd be in a separate project, but anything that works is good.
Thanks!

I can't comment (reputation too low) but is this what you want ?
http://www.cmake.org/pipermail/cmake/2006-May/009291.html
EDIT: if the above link stops working at some time, the idea is to add the files to Visual Studio like an ordinary source file. Since the IDE has no compile tool associated with it, it will be ignored. Quoting the list's discussion:
You could add arbitrary files to a target - as long as VS has no
"automatic" rule to compile them (e.g. .cc, .cpp etc)
I am adding .html files to libraries/executable or using a dummy target e.g:
ADD_EXECUTABLE(dummy dummy.cpp
"${CMAKE_CURRENT_BINARY_DIR}/Doc/index.html")
SOURCE_GROUP command may be useful, too.
and also
I think you have to take care that they are added only to VS IDE
generator builds,
in particular NOT to makefiles.
Thus we are using something like this:
IF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
ADD_EXECUTABLE( hello ${SOURCES} ${HEADER} ${DOC})
ELSE (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
ADD_EXECUTABLE( hello ${SOURCES} )
ENDIF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
Credit to Jan Woetzel

Related

Have Intermediate CMake Files Appear in the IDE

I am developing a system of build scripts for CMake and have an issue with wanting to have intermediate CMakeLists.txt files appear in the IDE for easier search and edit.
I have a main CMake file that includes a directory that includes several subdirectories for libraries.
CMakeLists.txt
--- SubProjects:
-------CMakeLists.txt
-------ProjectAFolder:
----------CMakeLists.txt
-------ProjectBFolder:
----------CMakeLists.txt
-------ProjectCFolder:
----------CMakeLists.txt
In the SubProjects folder, the CMakeLists.txt is very simple and just includes the subproject folders one after the other:
SET(SUBDIRECTORIES ProjectAFolder
ProjectBFolder
ProjectCFolder )
foreach (subdirectory ${SUBDIRECTORIES})
add_subdirectory(${subdirectory})
endforeach ()
However, when I generate this in XCode or Visual Studio, the IDE does not include the intermediate CMakeLists.txt file anywhere because it does not belong to any individual library or executable target. What is the best way to include this somewhere so it appears in an IDE?
Depends on where you want the file to show up, since it doesn't belong to any target. You can simply add it to any existing target (just as you do with source files) or you can create a new custom target.
add_library(AnyExistingTarget <other source files> SubProjects/CMakeLists.txt)
Or create a custom target:
add_custom_target(MyIntermediateCMakeFiles SubProjects/CMakeLists.txt)
For Visual Studio, you could also use the built-in support for cmake. It will display the source tree in the IDE without any extra work.

Change cmake generated project files directory

I could not find any question that was helpful concerning my question, so here it is (or prove me wrong).
First: I do everything under Windows and build only for Visual Studio.
My Situation: I have my main directory which contains a "main" CMakeLists. So here is were to make the cmake call and it does not much itself:
cmake_minimum_required(VERSION 3.13.1)
project (EulerAdventureReinvented)
if (CMAKE_GENERATOR MATCHES Win64)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/Win64/")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/Win64/")
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin/Win64/")
else()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/Win32/")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/Win32/")
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin/Win32/")
endif()
add_subdirectory(source)
But it adds another CMakeLists in the source directory which does the setup for the "main" project. So it contains the add_executable call and I wanna keep it that way. But the problem is that it does write the vcxproj files, CMakeFiles dir into that source directory, but I want them in the root directory or... well just somewhere else.
Final Question: What do I need to set for this? I mean which variable is the one I want to change. I searched and found so many that I came to a point of trial and error and even then did not find my files somewhere else.
EDIT: I changed the title a bit to avoid confusion between build and generated files. I do not want to set the build path, since that is already done by the above code.
In CMake 3.13.2 the following switches are available:
cmake [<options>] -S <path-to-source> -B <path-to-build>
So in the case you described above it would be something like:
cmake -S . -B .\build
Now, there is no variable for setting <path-to-build> but you can get it's information from CMAKE_BINARY_DIR. The variables you are setting control where artifacts wind up but not where project files are created or intermediate files are located.

How does Visual Studio know my project is up to date so it can skip running MSBuild?

I have a custom MSBuild target included in my C++ project that produces a data file in the $(OutDir) folder for each item of a given item type. I have the item type hooked up with a property page schema so you can select it on files in the solution explorer and my target declares input and outputs so incremental builds work. I have also added my target to the $(BuildDependsOn) property so it is automatically evaluated during the Build target Visual Studio invokes.
Everything seems to work except for one thing: If I delete one of my output data files in the $(OutDir) and then build Visual Studio does nothing and says my project is up to date. If I delete the exe file the project produces or touch the modified time of one of the MSBuild scripts Visual Studio re-evaluates the targts and finds the output file is missing, causing it to be re-built using my target.
From the MSBuild diagnostic logging it seems like Visual Studio is internally maintaining some list of output files and input files that it checks to avoid evaluating the MSBuild script at all. How do I add my output files to this list?
MsBuild/VS indeed have a mechanism to determine what is up-to-date with respect to the input files, it revolves around an executable tracker.exe which scans .tlog files to figure out what a project's output files are. There might be more to it, and if you look around on the internet you can probably get more info about this.
But the thing is you don't really need to understand every single detail of it: you can find a simple usage example for it when inspecting how the built-in CustomBuildStep works and apply that to your case. I'll briefly explain how I got to this because I think it might be useful for you as well in dealing with msbuild questions like these.
If you add
<ItemDefinitionGroup>
<CustomBuildStep>
<Command>echo foo > $(OutDir)\foo.txt</Command>
<Outputs>$(OutDir)\foo.txt</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
either manually or via the project's property pages for Custom Build Step you'll see the beahviour is eactly what you need: if foo.txt is deleted a build will start, while a build is marked up-to-date if it is not (well, and when the rest of the outputs are also up-to-date).
Hence the key is to do what CustomBuildStep does under the hood, and figuring that out is just a matter of using your tool of choice to search all occurrences of CustomBuildStep in all files under C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120 (adjust path for platform/VS version used).
This leads us to Microsoft.CppCommon.Targets where the target named CustomBuildStep (mind you, that's the same name as the entry in the ItemDefinitionGroup above) invokes the actual CustomBuildStep command. It also has this particularily interesting bit:
<!-- Appended tlog to track custom build events -->
<WriteLinesToFile Encoding="Unicode"
File="$(TLogLocation)$(ProjectName).write.1u.tlog"
Lines="#(CustomBuildStep->'^%(Identity)');#(CustomBuildStep->MetaData('Outputs')->FullPath()->Distinct())"/>
So this writes the path of the Outputs to a .tlog file in the directory used by the tracker and makes it work as desired. Also see here for more information about the format.
tl;dr Use WriteLinesToFile to append full paths of your targets' outputs to a file like $(TLogLocation)$(ProjectName).write.1u.tlog. I'm saying like because write.tlog, write.u.tlog etc also work.
Visual Studio uses something called Visual Studio Common Project System (CPS) (https://github.com/Microsoft/VSProjectSystem) (VS 2017)
to manage projects, including build process.
Within CPS anything that implements IBuildUpToDateCheckProvider interface can be used
as a 'UpToDateChecker' for a project.
'UpToDateChecker' is invoked before invoking MsBuild. Its main purpose is to determine whether or not invoke MsBuild to build project, or to mark project as 'Up To Date' and skip msbuild all along.
This 'UpToDateChecker' is exactly what prints into diagnostic build output:
1>------ Up-To-Date check: Project: "ProjectName", Configuration:
Debug x86 ------ Project is not up-to-date: build input 'header.h' was
modified after build output 'a.out'. Input time: 12/27/2018 4:43:08
PM, Output time: 1/1/0001 2:00:00 AM
As for C++ Projects, for VS 2017 its default 'UpToDateChecker' is VCProjectBuildUpToDateCheck
( Microsoft.VisualStudio.Project.VisualC.VCProjectEngine.dll ).
As starter, it looks into tlogs directory ( usually something like Debug\x86\.tlog) for these files:
.lastbuildstate
unsuccessfulbuild
all '.read..tlog' - input files, marked as 'build input' in diagnostic build output
all '.write..tlog' - output files, marked as 'build output' in diagnostic build output
There's actually more checks, but most fails occur when checking these 4 types
The original question here relates to C++ projects, but for anyone finding this while searching for information about modern (SDK-style) C#/VB/F# projects, you can customise Visual Studio's fast up-to-date check as described in this document:
https://github.com/dotnet/project-system/blob/master/docs/up-to-date-check.md
In a nutshell, you specify inputs and outputs as items:
UpToDateCheckInput — Describes an input file that MSBuild would not otherwise know about
UpToDateCheckBuilt — Describes an output file that MSBuild would not otherwise know about
It can be very helpful to increase the diagnostic logging level for the up-to-date check via this setting:
You can find out why a project is being rebuilt by enabling the verbosity of the fast up to date checker in the registry key:
New-ItemProperty `
-Name U2DCheckVerbosity `
-PropertyType DWORD -Value 1 `
-Path HKCU:\Software\Microsoft\VisualStudio\14.0\General -Force
You should be able to see in the build log messages like
Project 'Caliburn.Micro.Silverlight.Extensions' is not up to date. Project item 'C:\dev\projects\Caliburn.Micro.Silverlight.Extensions\NavigationBootstrapperSample.cs.pp' has 'Copy to Output Directory' attribute set to 'Copy always'.
[1] https://blogs.msdn.microsoft.com/kirillosenkov/2014/08/04/how-to-investigate-rebuilding-in-visual-studio-when-nothing-has-changed/
To enable logging for old-style projects (i.e. non-SDK-style projects, common in the .NET Framework era):
Open a "Developer Command Prompt" for the particular version of Visual Studio you are using.
Enter command:
vsregedit set "%cd%" HKCU General U2DCheckVerbosity dword 1
The message Set value for U2DCheckVerbosity should be displayed.
Run the same command with a 0 instead of a 1 to disable this logging.
More information at: https://github.com/dotnet/project-system/blob/main/docs/up-to-date-check.md#net-framework-projects

How to get path to object files with CMake for both multiconfiguration generator and makefile based ones?

I would like to generate a module definition file based on all symbols available in object files in dynamic fashion (think of GTKMM's gendef).
For this, I would like to add_custom_command for PRE_LINK step of a target. However, it looks like there is no easy way to get path to all object files with CMake that would work for plain makefiles as well as for multi-configuration generators like Visual Studio.
Right now, I have the following
add_custom_command(TARGET tgt PRE_LINK
COMMAND gendef ${CMAKE_CURRENT_BINARY_DIR}/tgt.def $<TARGET_FILE_NAME:tgt> ${CMAKE_CURRENT_BINARY_DIR}/$<$<BOOL:${CMAKE_BUILD_TYPE}>:${CMAKE_FILES_DIRECTORY}>/tgt.dir/${CMAKE_CFG_INTDIR}/*.obj
)
However this is quite awkward and bulky as I have to use generator expression in my opinion. Is there a better way to achieve this effect, i.e. call a certain external program for each build configuration?
Is it a CMake bug (feature?) that for plain makefiles, all object files go to CMakeFiles/tgt.dir folder while for multiconfiguration generators all goes to a sibling of CMakeFiles, i.e. tgt.dir/$<CONFIG>? Did I miss some simple variable that would point me to the right place directly?
Turning my comment into an answer
Makefile projects generated by CMake have a totally different internal structure then solutions/projects generated for Visual Studio. I think this is neither a bug nor a feature, those structures are just optimized for their usecases.
And as far as I know there is no easy CMake internal way to get the list of object files or the path to the intermediate files directory with e.g. reading a target property.
So I have taken your code example and have done some testing for alternatives with CMake 3.3.2 using Visual Studio 14 2015 and NMake Makefiles generators.
Alternatives
One related discussion on the CMake mailing list named "CMake: Is there an elegant way to get list of object files participating into a library?" does suggest using an intermediate static library:
add_library(tgtlib STATIC tgt.c)
add_custom_command(
OUTPUT tgt.def
COMMAND gendef tgt.def $<TARGET_FILE_NAME:tgt> $<TARGET_FILE:tgtLib>
)
file(WRITE dummy.c "")
add_library(tgt SHARED dummy.c tgt.def)
target_link_libraries(tgt tgtlib)
You could add build environment specific elements to your PRE_LINK step:
if(CMAKE_CONFIGURATION_TYPES)
set(_obj_files "$(IntermediateOutputPath)*.obj")
else()
set(_obj_files "$?")
endif()
add_custom_command(
TARGET MainProject
PRE_LINK
COMMAND gendef tgt.def $<TARGET_FILE_NAME:tgt> ${_obj_files}
)
References
NMAKE: Filename Macros

Multiple CMake Projects in one CMakeLists.txt

I want to have two projects that build off the same source files, with the second one just having a small subset, and a few different defines and build flags.
When I try something like this:
SET (this_target PROJECT1)
PROJECT(${this_target})
...
ADD_EXECUTABLE(#{this_target} ...)
SET (this_target PROJECT2)
PROJECT(${this_target})
...
add_definitions (-DMYDEFINE)
TARGET_LINK_LIBRARIES( ${this_target} -myflag )
ADD_EXECUTABLE(#{this_target} ...)
It ends up creating two projects, with seemingly the proper source files and the like, but for some reason, at least in Visual Studio 2010, both projects seem to get MYDEFINE defined and myflag in the linker flags.
I'm not sure why it seems to work for files, but not flags.
Firstly, you must use different names for your executables
If you want to add specific definitions to your targets, you may use set_target_properties, so each target will have their own properties (for example, compile definitions).
# compile and link first app
add_executable(prg1 ${CommonSources} ${Prg1SpecificSources})
target_link_libraries(prg1 lib1 lib2 lib3)
#set target-specific options
set_target_properties(prg1 PROPERTIES COMPILE_DEFINITIONS "FOO=BAR1")
#...
# compile and link second app
add_executable(prg2 ${CommonSources} ${Prg2SpecificSources})
target_link_libraries(prg2 lib1 lib2 lib3)
#set target-specific options
set_target_properties(prg1 PROPERTIES COMPILE_DEFINITIONS "FOO=BAR2")
If you want to override linking flags, you may use set_target_properties with LINK_FLAGS
I've found that putting multiple targets in one CMakeLists.txt causes intermittent build failure on Visual Studio 2010, due to colliding accesses to generate.stamp (though I can't rule out that I'm doing something wrong). Thus, you may have to put the targets in different CMakeLists.txt files, or find some other workaround.

Resources