how to set Visual Studio CMake project run time environment variable? - c++

Visual Studio 2022 CMake project
I build a qt cmake project in vs2022, everything works well, but when last step to run exe, it says the error of lack of dll files. I know that this is the problem of dll file directory. I can add it to system env path, or copy dll to exe file dir, but I guess that additional way that not mucks system env exists. I notice that VS traditional project can set debugger env in property, which set a local env variable, but I cannot find the way to set this in new support CMake Project in VS2022.
The IDE QtCreator also provide an analogous way that set env var for only project to run exe file, so any way to set this in VS like the traditional sln project, I search and find that some configure json file may help, but I cann't find precise setting.
As above, I guess some ways exist to set exe runtime env var to find dll file in VS CMake project, anyone could give me any tip, any helpful advice would be highly appreciated!

Finally, I found the way for cmake project without solutions in visual studio,
find launch.vs.json file by this
add custom env variable path to json file
add following content to project in configurations key:
"env": {
"PATH": "<dll-file-path>"
}
It works well for me, hope this can help you.

You can add the following properties to your CMakeLists.txt file that contains the executable target:
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT <your_executable_target_name>)
set_property(TARGET <your_executable_target_name> PROPERTY VS_DEBUGGER_ENVIRONMENT "PATH=${QTDIR}/bin")

If you need a build system independent solution, adding a custom target that simply launches the program could be an option:
Helper script (run_program.cmake)
set(ENV{PATH} "${PATH}")
execute_process(COMMAND "${PROGRAM}")
Actual project
add_executable(MyProgram ...)
add_custom_target(RunMyProgram COMMAND ${CMAKE_COMMAND} -D "PROGRAM=$<TARGET_FILE:MyProgram>" -D "PATH=${QT_BINARY_DIR};$ENV{PATH}" -P ${CMAKE_CURRENT_SOURCE_DIR}/run_program.cmake)
This allows you to use e.g.
cmake --build build_dir --target RunMyProgram --config Release
after building to run the program with the modified PATH environment variable.
Another option would be to use add_test + ctest, to run the program with a modifier environment, but this could easily render real test cases unuseable.

Related

Get the CMake build directory when setting a Conan package as editable

I'm trying to deduce the build directory of a local Conan package that's built using CMake so that I can set things like the lib and bin directories for when the package is set to editable mode. In essence, I want to be able to do the following:
def package_info(self):
self.cpp_info.libs = [f"{self.name}"]
# for Conan editable mode
if not self.in_local_cache:
self.cpp_info.includedirs = glob.glob("sources/*/include")
self.cpp_info.libdirs = [f"{cmake_build_dir}/{self.settings.build_type}"]
self.cpp_info.bindirs = [f"{cmake_build_dir}/{self.settings.build_type}"]
The problem is I don't see a way to set that cmake_build_dir variable other than through convention. Internally, we are already using a convention of putting checked in code within a sources folder, which is where the CMakeLists.txt file lives, and making a build/win folder, which is where we run the CMake command from (cmake ..\..\sources -A x64 -G "Visual Studio 15" to generate a Visual Studio solution). However, this is only a convention, and I'd like it to use the actual directory structure instead, especially since cross platform builds will necessary in the future.
I've tried printing out a few variables from an editable package to see if I can get anything useful. self.build_folder seemed like the most obvious, but it's empty inside the package_info method. I also tried to create a CMake object like is done in the build method (cmake = CMake(self)), but that just produced an error because self doesn't have the replace attribute either. The best I could do is get the folder that contains the conanfile.py with self.recipe_folder.
Is there an easy way to get the build folder from Conan/CMake, or do I just have to force a convention on my fellow developers in order to set packages as editable?

What is the command line used by CLion when invoking CMake?

What is exactly the command line (process and arguments) used by CLion when invoking CMake? I'm trying to use the same directory for manual builds using the terminal and for building using the IDE, but it seems that one is interacting badly with the other.
I have no problem with using CLion only to handle CMake configurations (to avoid slight configuration mismatch triggering another CMake execution), but it seems that even standard builds using make on the command line trigger cmake again.
I've seen that CLion prints it's "call" to CMake, but I don't see where it references the current working directory. And since on the GUI you configure paths relative to the project root folder (where CMakeLists.txt live), instead of relative to the build folder. I was hoping that this detail is the culprit here.
Usually in the command line I'd do it like this:
$ cd project
$ mkdir -p builds/debug
$ cd builds/debug
$ cmake $MY_CMAKE_OPTS -DSPECIAL_FILE=../../file.ext ../..
On CLion, though, I have to configure it like this:
CMake options: $MY_CMAKE_OPTS -DSPECIAL_FILE=file.ext
Generation path: builds/debug
The rest I've used the default
This special file is used on the configuration phase, so using paths other than relative to project root or absolute paths won't work.
Configuration step command line is shown in CMake view when you load/reload a CMake project: View - Tool Windows - CMake. The view has no default hotkey.
Example: /Users/vic/bin/cmake_ninja_wrapper.py -DCMAKE_BUILD_TYPE=Debug -G "CodeBlocks - Unix Makefiles" /Users/user/src/helloworld.
Depending on configuration, the current directory can be PROJECT_SOURCE_DIR/cmake-build-debug (where the build files were generated for me), PROJECT_SOURCE_DIR/cmake-build-release, or other.
Build step command line is shown in Messages - Build view. It opens when you invoke build from Build menu. I don't think the current directory matters for it, as all the build files are already generated.
Example: /Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake --build /Users/user/src/helloworld/cmake-build-debug --target helloworld -- -j 6
Then the view can be opened with Cmd-0 on Mac, or through menu: View -
Tool Windows - Messages.
To work with relative paths, you can refer to PROJECT_SOURCE_DIR variable in your CMakeLists.txt.

CMake post build step: copy multiple files dependent on visual studio configuration

I'm trying to write a CMakeLists.txt which copies as a post build event required dlls from external libraries to the folder in which the executable is located after building. The OS I'm working on is Win7 and VS2010.
There a quite a lot of external libraries, so I do not want to list them individually within the CMakeLists.txt. My current solution is to use file globbing and create a post build event for each library:
FILE(GLOB files "${LIBRARY_DIR}/lib/$(ConfigurationName)/*dll")
MESSAGE("FILE LIST IS: ${files}")
FOREACH(file ${files})
ADD_CUSTOM_COMMAND(
TARGET mylib
POST_BUILD
COMMENT "Copying dll ${file}..."
COMMAND ${CMAKE_COMMAND} -E copy ${file} "${CMAKE_BINARY_DIR}/$(ConfigurationName)/"
)
ENDFOREACH()
Basically, the code snipped above works file if I replace $(ConfigurationName) with Release or Debug. However, I'd like to take the libraries from the corresponding directory dependent on Release or Debug build mode. In the code snipped above, $(ConfigurationName) does not get substituted by the visual studio build mode. I guess this is due to that this is a VS2010 variable which isn't known at cmake generation time).
Does somebody have a smart idea how to resolve this issue?
ADD_CUSTOM_COMMAND understands generator expressions, so you would be able to use $<CONFIG> rather than $(Configuration) or $(ConfigurationName) there. For the FILE command, however, this won't work. More importantly though, the file globbing approach isn't going to work for the first time you build your project if those DLL's are built as part of the same project, since none of the DLL's would be there when you first run CMake in such an arrangement.
You may want to look into BundleUtilities as a more robust way to solve your problem. Despite its name, it supports all platforms, not just Mac. You would need to invoke the fixup_bundle command as a post-build or install step to achieve what you describe. There are a few variations of this approach already described online (e.g. here and here).
You can also have a look at the source for the DeployQt4.cmake file which should be included in the Modules subdirectory of your CMake installation for ideas.
Lets suppose you have _TARGET_NAME filled with your your project name, and ADDITIONAL_DLL_PATH with a list of folders containing external dlls, Then the following code will copy any external dependencies found using dumpbin on windows.
foreach(CONF_TYPE ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${CONF_TYPE} CONF_TYPE_U)
get_property(TARGET_LOCATION_${CONF_TYPE_U} TARGET ${_TARGET_NAME} PROPERTY LOCATION_${CONF_TYPE_U})
get_filename_component(TARGE_DIR ${TARGET_LOCATION_${CONF_TYPE_U}} PATH)
install(CODE "
if (\"\${BUILD_TYPE}\" STREQUAL \"${CONF_TYPE}\")
include(BundleUtilities)
fixup_bundle(\"${TARGET_LOCATION_${CONF_TYPE_U}}\" \"\" \"${ADDITIONAL_DLL_PATH}\")
endif()"
COMPONENT Runtime)
endforeach()
There are downsides to this solution though, Like the need to build INSTALL target whenever you need to copy those files (which might not be many times), and not detecting delay loaded dlls.

Netbeans project imported from existing cmake application fails to build with filesystem error on Windows

I am attempting to import a manually-created cmake project that I had been using in a different IDE into Netbeans 8.0.2 on Windows 7. Needless to say, my cmake configuration worked fine there.
Netbeans seems to import the directory fine. I imported it in "automatic" (cmake) mode. However, when I attempt to build the project, I get a rather cryptic (Java?) error message:
Makefile:76: recipe for target 'all' failed
process_begin: CreateProcess(NULL, /C/MinGW/bin/make.exe -f CMakeFiles/Makefile2 all, ...) failed.
make (e=2): The system cannot find the file specified.
Knowing very little about Java, I am not sure how to interpret this error. The first directory (/C/MinGW/bin/make.exe) stands out to me as not being in Windows-format, but I am not sure if that's incorrect. I do indeed have a file by that name, as I copied the longer-named mingw make binary so I would only need to type "make".
Presuming this is being run in the project root, and that the first directory is formatted correctly, I don't see any problem with finding these files.
My CMakeLists.txt is:
cmake_minimum_required(VERSION 2.8.4)
set(Project_Name "Test")
set(Test_VERSION_MAJOR 1)
set(Test_VERSION_MINOR 0)
project(${Project_Name})
include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/inc"
"${CMAKE_CURRENT_SOURCE_DIR}/inc/SDL"
"C:/Users/Bakaiya/Documents/ogre/OgreMain/include"
)
file(GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
link_directories(${CMAKE_CURRENT_SOURCE_DIR} ${OPENGL_LIBRARIES})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_executable(${Project_Name} ${SOURCE_FILES})
target_link_libraries(${Project_Name} SDL2main SDL2 OgreMain) #Ogre
Running the "generate makefile" command in the IDE completes without issue, but does not fix the problem. Additionally, clean fails, but "help" does work.
This is a problem within the IDE, it seems, because if I run make from the command line in the project root, it builds without issue.
Also, I fiddled with the file path mode setting under C/C++ -> Project Options, and it did nothing. Even set to absolute, what seems to be a relative path (CMakeFiles/Makefile2) is still in the failed command. I'm not sure if that option is expected to change that sort of reference or not.
What could be wrong with this imported project to cause this issue?
However, when I attempt to build the project, I get a rather cryptic (Java?) error message:
This is an error shown by netbeans to tell you, that it was unable to execute make command successfully. Usually this indicates a wrong setting of your (mingw-) tools.
Here are some points you can check:
Don't use make from mingw/bin, you have to use the one from mingw/msys/... There's a mingw make within mingw's msys folder, usually C:\<Path to MSYS>\<Version>\bin\make.exe - this bin-path must also be set in PATH environment variable! If MSys wasn't installed with your mingw installation, please install it.
Please check the tools set in Tools -> Options -> C/C++ -> Build Tools; you can test them by clicking Versions....
(If existing) Clean the CMake generated files and clean the cmake's cache. If not done yet, please use an out-of-source build as described here.
Can you build your project from terminal (without netbeans)?
The first directory (/C/MinGW/bin/make.exe) stands out to me as not being in Windows-format, but I am not sure if that's incorrect.
This is ok and intended by mingw - it uses linux / unix like paths.
Update
Which make program should I use?
Many MinGW users have a problem because they use mingw32-make.exe from
the MinGW installation. While this seems like the right choice, it
actually breaks the build. The problem is that this is a non-Posix
implementation of the Unix make program and doesn't work well at all.
In fact, thats why the MinGW people renamed it! They've also made a
FAQ entry explaining why you should not use mingw32-make.exe. Instead,
you should use the make.exe program from the MSYS package.
As of NetBeans 6.1, the Build Tools panel no longer allows a user to
select mingw32-make. If you choose a MinGW compiler collection it will
default to make in MSYS. If MSYS is not found, it will tell you no
make program has been found.
(http://wiki.netbeans.org/MinGWInCCDevelopmentPack)

How do I use CMake?

I am trying to use CMake in order to compile opencv.
I am reading the tutorial but can't understand what is CMakeLists files and how is it connected to the gui of CMake?
Also couldn't understand what are makefiles, are they the same is CMakeLists?
And which file is it which I in the end open with visual-studio?
I don't know about Windows (never used it), but on a Linux system you just have to create a build directory (in the top source directory)
mkdir build-dir
go inside it
cd build-dir
then run cmake and point to the parent directory
cmake ..
and finally run make
make
Notice that make and cmake are different programs. cmake is a Makefile generator, and the make utility is governed by a Makefile textual file. See cmake & make wikipedia pages.
NB: On Windows, cmake might operate so could need to be used differently. You'll need to read the documentation (like I did for Linux)
CMake takes a CMakeList file, and outputs it to a platform-specific build format, e.g. a Makefile, Visual Studio, etc.
You run CMake on the CMakeList first. If you're on Visual Studio, you can then load the output project/solution.
Yes, cmake and make are different programs. cmake is (on Linux) a Makefile generator (and Makefile-s are the files driving the make utility). There are other Makefile generators (in particular configure and autoconf etc...). And you can find other build automation programs (e.g. ninja).
CMake (Cross platform make) is a build system generator. It doesn't build your source, instead, generates what a build system needs: the build scripts. Doing so you don't need to write or maintain platform specific build files. CMake uses relatively high level CMake language which usually written in CMakeLists.txt files. Your general workflow when consuming third party libraries usually boils down the following commands:
cmake -S thelibrary -B build
cmake --build build
cmake --install build
The first line known as configuration step, this generates the build files on your system. -S(ource) is the library source, and -B(uild) folder. CMake falls back to generate build according to your system. it will be MSBuild on Windows, GNU Makefiles on Linux. You can specify the build using -G(enerator) paramater, like:
cmake -G Ninja -S libSource -B build
end of the this step, generates build scripts, like Makefile, *.sln files etc. on build directory.
The second line invokes the actual build command, it's like invoking make on the build folder.
The third line install the library. If you're on Windows, you can quickly open generated project by, cmake --open build.
Now you can use the installed library on your project with configured by CMake, writing your own CMakeLists.txt file. To do so, you'll need to create a your target and find the package you installed using find_package command, which will export the library target names, and link them against your own target.
Cmake from Windows terminal:
mkdir build
cd build/
cmake ..
cmake --build . --config Release
./Release/main.exe
Regarding CMake 3.13.3, platform Windows, and IDE Visual Studio 2017, I suggest this guide. In brief I suggest:
1. Download cmake > unzip it > execute it.
2. As example download GLFW > unzip it > create inside folder Build.
3. In cmake Browse "Source" > Browse "Build" > Configure and Generate.
4. In Visual Studio 2017 Build your Solution.
5. Get the binaries.
Regards.