CMake putting build files in source directory - cmake

I am very new to CMake. A friend wrote a simple CMakeLists.txt for the project I am coding myself. I am using svn and have just checked out an old version on the same machine into a different folder. Now, in the original source directory (where CMakeLists.txt is located) I create the directory 'build', cd into there, and for the time being run the code
cmake -DCMAKE_BUILD_TYPE=Debug ..
This nicely puts all of the files in the build directory
-- Build files have been written to: ~/MixedFEMultigrid/build
Now when I check out to another directory, create another 'build' directory in that one and then run the CMake command I get the following
-- Build files have been written to: ~/oldCode
where oldCode is actually the parent directory. I have no idea why this is happening. Can someone explain this to me? The full CMakeLists.txt file is given below,
cmake_minimum_required (VERSION 2.6)
project (MixedFEMultigrid)
FIND_PACKAGE(LAPACK REQUIRED)
set( SRC_FILES multigrid.c
gridHandling.c
interpolation.c
linApprox.c
params.c
sparseMatrix.c
testing.c
richardsFunctions.c
definitions.c
newtonIteration.c
)
#Adds the executable with all the dependencies
add_executable (multigrid ${SRC_FILES})
#Specifies the libraries to link to the target
TARGET_LINK_LIBRARIES(multigrid ${LAPACK_LIBRARIES} m)
# Update if necessary
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -fstrict-aliasing -std=c99 -O3")
As per the comment by escrafford I am updating to show what I do on the command line.
cd ~
mkdir oldCode
cd oldCode
svn co <repository>
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
The build files are then put into the directory 'oldCode' instead of the 'build' directory. The following, on the other hand, puts the build files into the 'build' directory
cd ~
mkdir MixedFEMultigrid
cd MixedFEMultigrid
svn co <repository>
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..

That comes from a in-source cmake execution
Remember to remove cmake cache:
$ rm CMakeCache.txt
$ mkdir debug
$ cd debug
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
That has another benefit, given that cmake do not provide a clean target
$ cd ..
$ rm -rf debug
is the equivalent of make clean or more precisely make distclean

Related

Is it possible to determine whether CMake install(CODE) is called from the "install" or "package" stage?

I'm using CMake v3.21.0 to invoke Qt's windeployqt during the install stage by the means of the install(CODE) command as follows:
install(
CODE "
execute_process(
COMMAND \"${CMAKE_COMMAND}\" -E
env PATH=\"${windeployqt_ROOT_DIR}\"
\"${windeployqt_EXECUTABLE}\"
# TODO(2021-08-25 by wolters): This is a different path when CPack is`
# used. How to check for this case and obtain the correct output path?
--dir \"${CMAKE_INSTALL_PREFIX}/${args_INSTALL_SUFFIX}\"
--no-quick-import
--no-system-d3d-compiler
--no-virtualkeyboard
--no-compiler-runtime
--no-webkit2
--no-angle
--no-opengl-sw
--verbose 0
\"\$<TARGET_FILE:${args_TARGET}>\"
)
"
COMPONENT runtime
)
This works fine if installing the project:
cmake --build . --config RelWithDebInfo --target install
But when creating a CPack package the files created by windeployqt are not part of the package (ZIP in this case):
cpack -G ZIP -C RelWithDebInfo -D CPACK_COMPONENTS_ALL="runtime"
I know that the issue is the usage of ${CMAKE_INSTALL_PREFIX} in the CODE.
For the install target this is correct.
For the package target this is not correct. Instead the build directory for the current CPack generator should be used, e.g. ${CMAKE_CURRENT_BINARY_DIR}/_CPack_Packages/win64/ZIP/${CPACK_PACKAGE_FILE_NAME}.
My questions are:
Is there a way to differentiate between install and package target in the CODE section? (pseudo-code: if(CMAKE_IS_PACKAGING))
If there is a way: Is it possible to obtain or dynamically build the directory path to the actual CPack temporary "install" directory?
If both problems can be solved the files generated by windeployqt should be part of the packages generated by CPack.
The variable CMAKE_INSTALL_PREFIX should not be expanded in the CMakeLists.txt, as you are doing. Its actual value at invocation time is available inside the install(CODE) fragments.
Consider the following snippet:
cmake_minimum_required(VERSION 3.21)
project(test NONE)
install(CODE [[message(STATUS "HERE: ${CMAKE_INSTALL_PREFIX}")]])
Note that [[ ... ]] escapes variable expansions (you could also use backslashes). Now if you configure this project with -DCMAKE_INSTALL_PREFIX=/tmp/install, you'll see the message print as you expect.
$ cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/tmp/install
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --target install
[0/1] Install the project...
-- Install configuration: ""
-- HERE: /tmp/install
If you now run the install script again without reconfiguring or rebuilding, it will still work:
$ cmake --install build/ --prefix /tmp/other-prefix
-- Install configuration: ""
-- HERE: /tmp/other-prefix
This is how CPack runs your install rules. It does not use the configuration-time value of CMAKE_INSTALL_PREFIX. It expects your project to be relocatable (i.e. bug-free).

cmake ignoring CMAKE_INSTALL_PREFIX inside CMakeLists.txt

I have a small project with a very simple CMakeLists.txt file. At the bottom of this file, I have the following lines:
set (CMAKE_INSTALL_PREFIX /opt/myprod)
message (STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
install (TARGETS myprod DESTINATION bin)
However, when I run:
sudo make install
I get the following:
[100%] Built target myprod
Install the project...
-- Install configuration: ""
-- Up-to-date: /usr/bin/myprod
-- Up-to-date: /usr/bin/myprod
cmake always puts my executable under /usr/bin when it should be under /opt/myprod/bin.
And, yes, the last line is always repeated. Does anyone know how I can fix this?
Using cmake 3.20.3 on Fedora 34.
Your issue cannot be reproduced with the level of detail you've given:
File CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(myprod)
add_executable(myprod main.cpp)
set(CMAKE_INSTALL_PREFIX /opt/myprod)
message (STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
install (TARGETS myprod DESTINATION bin)
File main.cpp
int main() { return 0; }
Commands:
$ cmake -S . -B build
...
$ cmake --build build/
$ sudo cmake --build build/ --target install
[sudo] password for alex:
[0/1] Install the project...
-- Install configuration: "Release"
-- Installing: /opt/myprod/bin/myprod
$ sudo rm -rf /opt/myprod/
So as you can see, /opt/myprod survived to the final output.
The install() command is responsible for generating the cmake_install.cmake script in the build directory. As far as I know, the very first one reads CMAKE_INSTALL_PREFIX, so you must have another call to install() in your project that you aren't showing us.
Furthermore, you should not set CMAKE_INSTALL_PREFIX inside the CMakeLists.txt; it is designed to be set externally as a cache variable. Hard-coding it is bad because someone else might wish to install your project to a different location besides /opt. Maybe they're on a different operating system or Linux distribution. Maybe even your whims change. In any case, one shouldn't need to edit a file to change the install prefix.
Since you're using CMake 3.20, I strongly encourage you to move such settings to presets.

How to use CMake to build sources with ghdl as custom target?

I would like to build VHDL sources with CMake. For this I have a directory structure:
<root>
- CMakeLists.txt
- src/CMakeLists.txt
- src/mymodule.vhdl
- build
Inside the root CMakeLists.txt I have:
cmake_minimum_required(VERSION 3.12)
project(vhdlsdb LANGUAGES NONE)
add_subdirectory(src)
In the src/CMakeLists.txt I have:
set(filelist mymodule.vhdl )
add_custom_target(vhdlize COMMAND ghdl -a ${filelist})
However, when I run cd build && cmake .. -GNinja && cmake --build . --target vhdlize I get:
error: cannot open mymodule
C:\Users\pm\git\GHDL\0.36-mingw64-llvm\bin\ghdl.exe: compilation error
How can I tell CMake to copy or look for the sources in the src folder?

How to create a custom target that copies a library?

I am trying to create a custom target that just copies a library to the LIBRARY_OUTPUT_PATH. Below is my CMakeLists.txt.
The contents of the MYCOMPONENT folder is mylib.so and CMakeLists.txt.
cmake_minimum_required(VERSION 2.8)
project( MYCOMPONENT )
add_custom_target( MYTARGET
COMMAND ${CMAKE_COMMAND} -E copy ./mylib.so ${LIBRARY_OUTPUT_PATH} )
I do the following:
cd MYCOMPFOLDER
mkdir build_debug
cd build_debug
cmake -DLIBRARY_OUTPUT_PATH=<mycompfolderfullpath>/build_debug/bin ..
Now I do an ls of build_debug and I get:
CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
ls CMakeFiles/
3.5.1 CMakeTmp Makefile2
cmake.check_cache feature_tests.bin Makefile.cmake
CMakeDirectoryInformation.cmake feature_tests.c progress.marks
CMakeOutput.log feature_tests.cxx TargetDirectories.txt
CMakeRuleHashes.txt MYCOMPONENT.dir
ls CMakeFiles/MYCOMPONENT.dir/
build.make cmake_clean.cmake DependInfo.cmake progress.make
From build_debug, "find . -name mylib.so" is nowhere, so of course the "make MYTARGET" fails. How do I get cmake to properly handle mylib.so? This is a third party library, we don't build it, the target is to make sure it gets copied to the LIBRARY_OUTPUT_PATH from this folder so other components can link against it from there.
Don't use relative paths in -E copy part. Variables CMAKE_SOURCE_DIR, CMAKE_CURRENT_SOURCE_DIR, CMAKE_BINARY_DIR and CMAKE_CURRENT_BINARY_DIR are at your disposal.

Add custom commands to CMakeLists.txt file

Recently I have switched my project compilation procedure from make to cmake. I would like to add custom non-compilation related commands to my CMakeLists.txt file. These commands should be inherited from classical Makefile. Commands that I would like to re-use in CMakeLists.txt are:
CODE=main
ARCHIVE=$(CODE)_`date +%F`.tar.bz2
BACKUP=$(HOME)/backup/src/$(CODE)
run:
{ time ./$(CODE); } 2> $(CODE)_time
rerun: fresh run
fresh:
rm -rvf $(CODE)_time *~ fort.* *.ver
rm -rvf coef? enc skin_depths log input_params.out
clean: fresh
rm -rvf $(CODE) *.o *.a *.mod
backup: *
tar -cjvf $(ARCHIVE) $?
tar -tjvf $(ARCHIVE)
mv -vf $(ARCHIVE) $(BACKUP)
ls -lrth $(BACKUP)
How may I transfer these commands to CMakeLists.txt so that they will be automatically inserted into cmake generated Makefile?
CMakeLists.txt
# Minimum cmake version
cmake_minimum_required(VERSION 2.8)
# Project name
project(main Fortran)
# Toolchain selection, possible arguments: Intel, GNU
SET(Toolchain GNU)
# Compiler selection
include(CMakeForceCompiler)
# GNU compilers
if(${Toolchain} MATCHES GNU)
CMAKE_FORCE_Fortran_COMPILER(gfortran "GNU Fortran Compiler")
set(CMAKE_Fortran_FLAGS "-g -O0 -fimplicit-none -fbounds-check -fbacktrace ${CMAKE_Fortran_FLAGS}")
endif(${Toolchain} MATCHES GNU)
# Source code files
SET(src variables.F90
init.F90
io.F90)
# Main executable
ADD_EXECUTABLE(${PROJECT_NAME} ${src})
# EoF: CMakeLists.txt
Use the ADD_CUSTOM_TARGET and/or ADD_CUSTOM_COMMAND commands, e.g.:
ADD_CUSTOM_TARGET(myTarget
COMMAND firstCommand arg1 arg2
COMMAND secondCommand arg1 arg2 arg3)
Then you can use make myTarget.