How to ensure that the relative paths are the same in Linux and Windows using CMake [duplicate] - c++

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.

Related

Reading file in a c++ file in VS project [duplicate]

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.

why the relative path is different when I use Cmake build and VS 2019 build?

I'm new in Cmake. And I try to use Cmake to construct my project.
In my project, I need to load some resources in runtime. for instance:
string inFileName = "../Resources/resource.txt";
// string inFileName = "../../Resources/resource.txt";
ifstream ifs;
ifs.open(inFileName.c_str());
if (ifs) {
....
}
But when I use the command line cmake ../ and cmake --build . --config Release in project/build. my file path should be relative to ${PROJEDCT_BINARY}, i.e. inFileName = "../resources/resource.txt".
But when I use cmake ../ and open the sln file with VS2019 then right-click to build and run, my file path should be relative to the executable, i.e. inFileName = "../../resources/resource.txt".
I don't know why this happened, and I search through Internet, It seems no one else encounters this stupid question...
Below is my file structure.
|--3rdParty
|----CmakeLists.txt
|--include
|----header.h
|--source
|----source.cpp
|----CmakeLists.txt
|--resources
|----resource.txt
|--CmakeLists
and my root CmakeLists.txt
cmake_minimum_required(VERSION 3.12)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(OBMI VERSION 0.1.0.0 LANGUAGES C CXX CUDA)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
add_subdirectory(3rdParty)
add_subdirectory(source)
source/CmakeLists.txt
add_executable(mSI)
target_sources(mSI PRIVATE
${PROJECT_SOURCE_DIR}/include/header.h
# source
source.cpp
)
target_include_directories(multiSpectrumImaging
PRIVATE
${PROJECT_SOURCE_DIR})
target_link_libraries(mSI
PRIVATE
...
)
When using relative paths to load files, the resolution of the final filename depends on the current working directory. The relative path is appended to that working directory. That current working directory is not necessarily the same as the path of your application; it will be the path of the surrounding environment from which the application is started (or can be set specifically for a debug environment in most IDE's).
You don't specify exactly how you run your program when you run it not from the IDE - just by double-clicking the executable maybe? You also don't tell us where the executable is built in relation to your sources?
Specifically for running from Visual Studio, you can set the working directory in the "Debugging" section of the Project Properties.
For a more flexible solution, what I typically do is to determine the path of your executable, and then appending the relative path to load resources to that.
Basically, the full executable path is stored in argv[0] (if you have a int main(int argc, char** argv) {...}, i.e., the first element of the second argument to your main function). For more information on this, see for example the answers to this other question.
By generating an MSVS solution file you (CMake) create a working environment for MSVS where the solution (and projects) is generated. So everything relative there would be relative to those files generated and as far as MSVS is concerned, that directory is the center of the world. That's why you should strive to use absolute and not relative paths.
To achieve that CMake has a bunch of variables and PROJECT_SOURCE_DIR, which you use, is one of them. But there is one which seems to suite your case better case, though: CMAKE_SOURCE_DIR.
So whenever you need to use your resources, use the following path in your CMake script: "${CMAKE_SOURCE_DIR}/resources/resources.txt"
If you need your resources to load in runtime then it goes beyond CMake and its capabilities. You should put these resources relative to your resulting binary because what place they have in the project doesn't matter anymore. CMake helps with it by providing install and file(COPY ...). Where the former is mostly used during the packaging of your application and the latter might be used during development to ease the burden.
For example, you can have the following in your project (source/CmakeLists.txt) CMake file:
file(COPY "${CMAKE_SOURCE_DIR}/resources" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
Which should place the resources folder where your binary gets created.

Debugging CMake Visual Studio project with PATH environment set by VS_DEBUGGER_ENVIRONMENT

I've created a CMake project using visual studio 2019. It has one executable target, which links to some shared libraries (DLL). I cannot directly set the system environment variable PATH because the DLL path is determined by find_package. Therefore, set VS_DEBUGGER_ENVIRONMENT target property is my choice to debug that executable target.
However, the VS_DEBUGGER_ENVIRONMENT property is not working when I directly open the CMake project and debug that target. I've checked the .vsproj it has the correct LocalDebuggerEnvironment tag generated.
But if I run cmake -G "Visual Studio 16 2019" ../ and open the generated visual studio solution and then debug the subproject from there, everything turns out to be ok.
I think maybe the visual studio doesn't support LocalDebuggerEnvironment when opening project as a CMake project. Or perhaps I didn't debug it the right way. Is there anything else I can do to change the visual studio debug runtime PATH environment using CMake?
Any suggestion would be greatly appreciated!
This is just to share what I finally ended up with after some painful hours of digging through the web.
First, a variable to store the required debugging paths is needed (example):
list(APPEND VS_DEBUGGING_PATH "%PATH%")
list(APPEND VS_DEBUGGING_PATH "${PostgreSQL_ROOT}/bin")
The next step is to create a ${CMAKE_PROJECT_NAME}.vcxproj.user template file for C/C++ and in my case also a ${CMAKE_PROJECT_NAME}.vfproj.user template for FORTRAN (just for the record):
file(
WRITE "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.vcxproj.user"
"<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">
<PropertyGroup Condition=\"'\$(Configuration)'=='Release'\">
<LocalDebuggerEnvironment>PATH=#VS_DEBUGGING_PATH#</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition=\"'\$(Configuration)'=='MinSizeRel'\">
<LocalDebuggerEnvironment>PATH=#VS_DEBUGGING_PATH#</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition=\"'\$(Configuration)'=='RelWithDebInfo'\">
<LocalDebuggerEnvironment>PATH=#VS_DEBUGGING_PATH#</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition=\"'\$(Configuration)'=='Debug'\">
<LocalDebuggerEnvironment>PATH=#VS_DEBUGGING_PATH#</LocalDebuggerEnvironment>
</PropertyGroup>
</Project>"
)
file(
WRITE "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.vfproj.user"
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<VisualStudioUserFile>
<Configurations>
<Configuration Name=\"Release|x64\" Environment=\"PATH=#VS_DEBUGGING_PATH#\"/>
<Configuration Name=\"MinSizeRel|x64\" Environment=\"PATH=#VS_DEBUGGING_PATH#\"/>
<Configuration Name=\"RelWithDebInfo|x64\" Environment=\"PATH=#VS_DEBUGGING_PATH#\"/>
<Configuration Name=\"Debug|x64\" Environment=\"PATH=#VS_DEBUGGING_PATH#\"/>
</Configurations>
</VisualStudioUserFile>"
)
As you might see, both template files are just dumped into the root of ${CMAKE_BINARY_DIR} in this case. The base name ${CMAKE_PROJECT_NAME} is also arbitrary.
Those templates can then finally be "configured" (copied) into each target folder of your setup. Either for C/C++
configure_file(
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.vcxproj.user"
"${CMAKE_CURRENT_BINARY_DIR}/${target_name}.vcxproj.user"
#ONLY
)
or FORTRAN
configure_file(
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.vfproj.user"
"${CMAKE_CURRENT_BINARY_DIR}/${target_name}.vfproj.$ENV{USERNAME}.user"
#ONLY
)
or even both if necessary. The variable ${target_name} needs to replaced with your target name of course. :-)
This should suffice. It is however important to close VS 2019 before (re-)configuring/(re-)generating with CMake. Otherwise VS 2019 might simply overwrite those files for each target.
I strongly hope this is helpful.
Please let me know if you need more details.
Here is the result for C/C++ targets and here for FORTRAN targets

Custom CMake target that uses only CMake functions [duplicate]

I have a project under CMake with some files generated with python generator from XML files. I cannot specify all files generated by this generator in CMakeLists.txt so I use file globbing for this.
The problem is that when I update my XML files or generator sources (which are in the same repository) I would like to have my build system reconfigured so changed files are taken into account when rebuilding the code (via make for example).
Is it possible to make CMake treat some files like it treats CMakeLists.txt files and to make it regenerate build system when those file are changed?
It doesn't require any kind of workarounds. The standard way is to use CMAKE_CONFIGURE_DEPENDS property:
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS <filename>)
Yes, you should be able to do that by (ab)using configure_file(). Configuring a file makes the source a dependency of the CMake run, so that any changes in it cause a reconfiguration. Simply like this:
configure_file(MyInputFile.xml DummyOutput.xml)
Since it has been a while I will add to #roolebo's answer.
There's actually a better command to add a dependency on a file:
set_directory_properties(PROPERTIES CMAKE_CONFIGURE_DEPENDS <relative_or_full_path_to_file>)
What might be confusing is that this command adds a property to the current directory. Well, it does not matter since you can set a full path to a file that resides outside of the current directory's scope, for instance: ../../config.json

CMake command line for C++ #define

I need to compile different versions of a certain project by adding compiler switches. Usually I would do this by using add_definitions or something like
set_property( TARGET mylib PROPERTY COMPILE_DEFINITIONS _MYDEFINE=1 )
in the CMakeLists.txt file.
In this specific project however, I am not allowed to modify any sources, including the CMakeLists.txt file.
I was hoping that something like
cmake -D_MYDEFINE=1 <path to sources>
would generate a project file (Visual Studio 2008 in my case, but shouldn't matter) which includes _MYDEFINE=1 in its preprocessor definitions but in fact it won't.
What are my options here? Is there a different cmake command line option to achieve this? Feel free to suggest solutions not including the command line, as long as changing the project's CMakeLists.txt is not necessary.
I managed to do it this way now:
I was able to convince everybody to add the following lines to the common CMakeLists.txt:
IF (NOT DEFINED _MYDEFINE)
SET(_MYDEFINE <default value>)
ENDIF()
ADD_DEFINITIONS(-D_MYDEFINE=${_MYDEFINE})
(No it is not really called "MYDEFINE", and <default value> is just a placeholder, I just replaced all that for this example)
This does not change the current behaviour of compiling with no additional compiler flags and is thus a valid change.
And it allows you to do
cmake -D_MYDEFINE=<my value> <path to sources>
where this cmake definition will be mapped to a C++ precompiler definition when cmake creates the project file.
Container CMakeLists.txt solution
Tricky solution:
Your read only CMakeList.txt path: ${path}/ReadOnlyProject/CMakeLists.txt
Create a new CMakeList.txt to upper to the read only library (${path}/CMakeLists.txt):
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)
PROJECT (FAKE_PROJECT)
ADD_DEFINITIONS(-D_MYDEFINE=1)
ADD_SUBDIRECTORY(ReadOnlyProject)
Now use your new project (FAKE_PROJECT) to compile. If the ReadOnlyProject does not set compilers definitions directly, it could work.
On Visual Studio 2010:
Try to modify c:\Users\${username}\AppData\Local\Microsoft\MSBuild\v4.0\Microsoft.Cpp.Win32.user.props to add custom compiler settings.
You should add the followings:
<Project>
...
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>__MYDEFINE=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project>
To pass a C++ or C pre-processor define without modifying any CMake source files, use the environment variables CFLAGS for C or CXXFLAGS for C++ respectively, e.g.:
$ export CXXFLAGS="-D_MY_DEFINE=1 -D_MY_OTHER_DEFINE=1"
$ mkdir build
$ cd build
$ cmake ..