CMAKE build gui application with MinGW - cmake

I want to build gui application with SDL2. I link SDL2 libraries(libSDL2.dll.a and libSDL2main.a) but I don't know how a can apply -mwindows flag to my application. Without him .exe file of my application doesn't show window (executing have not any effect). I use MinGW-w64 my OS is Windows 10. In command line I can do this like here (see section B). How I can apply this flag with usage cmake? Console application works fine.
I try next variant but it doesn't work.
cmake -G "MinGW Makefiles" -D CMAKE_C_COMPILER=gcc -D CMAKE_CXX_COMPILER=g++ -D CMAKE_EXE_LINKER_FLAGS="-mwindows"
cmake -G "MinGW Makefiles" -D CMAKE_C_COMPILER=gcc -D CMAKE_CXX_COMPILER=g++ -D CMAKE_CXX_FLAGS="-mwindows"
Also in CMakeLists.txt I try do like this
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows")

You can pass WIN32 argument to add_executable and CMake will do this for you:
add_executable(target_name WIN32 ${sources})

I basically copy-pasted the stuff, which CLion executes in the command line, and it worked:
$ cmake DCMAKE_BUILD_TYPE=Debug -G "CodeBlocks - MinGW Makefiles" ../
$ cmake --build ./ --target target_name -j 6
[ 50%] Building CXX object CMakeFiles/target_name.dir/main.cpp.obj
[100%] Linking CXX executable target_name.exe
[100%] Built target tree_traverse
After this the executable target_name.exe appeared in the directory.

Related

CMAKE how to pass arguments to msbuild.exe

I have a cmake project and I'm using the msvc 2019 generator on windows 10.
I can successfully build with the following:
cmake -S . -B build
cd build
cmake --build . -- /m
I'm interested in passing the /m switch to msbuild.exe within the CMakeLists.txt itself.
I've tried the following without success as arguments get passed to cl.exe:
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /m")
message(STATUS "NOTICE: Setting parallel build for msbuild.exe")
add_definitions(/M)
endif()
Also bonus question: How does -- work in the last cmake command above? I'm struggling finding documentation on it.
The answer as #Johnny_xy pointed out is you can't. You need to use ninja as the cmake generator.
cmake -S . -B build -G Ninja Multi-Config
cd build
cmake --build .
link to ninja releases:
https://github.com/ninja-build/ninja/releases
ninja build time: 17.51s
cmake default build time: 44.54s

How to build executable with a compiler from ExternalProject

I have an external project that generates a compiler
include(ExternalProject)
ExternalProject_Add(gprolog
GIT_REPOSITORY "git#github.com:didoudiaz/gprolog.git"
GIT_TAG "master"
SOURCE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/gprolog"
BUILD_IN_SOURCE true
CONFIGURE_COMMAND cd src && ./configure --with-install-dir=${CMAKE_SOURCE_DIR}/3rdparty/gprolog-build
BUILD_COMMAND cd src && make
INSTALL_COMMAND cd src && make install
)
Consequently, I'd like to run:
add_executable(runner src/runner.c app/application.pro)
include_directories(runner "${CMAKE_SOURCE_DIR}/3rdparty/gprolog-build/include")
but instead of gcc or clang, I need to use ${CMAKE_SOURCE_DIR}/3rdparty/gprolog-build/bin/gplc.
When I politely ask CMake to pretend that gplc is just another C compiler by adding
set(CMAKE_C_COMPILER "${CMAKE_SOURCE_DIR}/3rdparty/gprolog-build/bin/gplc")
it screams at me with
Cannot get compiler information:
Compiler exited with error code 1: .../gprolog/3rdparty/gprolog-build/bin/gplc -xc -g -isysroot ..../Developer/SDKs/MacOSX11.3.sdk -fpch-preprocess -v -dD -E
Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: x86_64-apple-darwin20.5.0
Thread model: posix
InstalledDir: .../XcodeDefault.xctoolchain/usr/bin
clang: warning: -lm: 'linker' input unused [-Wunused-command-line-argument]
clang: error: cannot specify -o when generating multiple output files
compilation failed
Short of reverse engineering CMake's enable_language implementation modules to add your own for Prolog, you can always go the route of add_custom_command and ask your compiler to generate object files, which can be included as sources in the add_executable command.
If you add some detail to the question about how the Prolog compiler works, I can help you write the custom commands.

CMake: Building a object file from a source in a object library in a sub directory out of source

Consider the following mock project with these files:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(myproject)
add_subdirectory(sub)
# sub/CMakeLists.txt
add_library(myLib OBJECT bar.c)
add_executable(foo foo.c)
target_link_libraries(foo PRIVATE myLib)
# sub/foo.c
int main() {return 0;}
# sub/bar.c
void bar(){}
When building in source after cmake -G Unix\ Makefiles -B . -S . I can go to the the directory sub and execute make bar.o. How can I achieve the same results when building out of source? I've tried these commands from the project root:
cmake -G Unix\ Makefiles -B test-build -S .
cmake --build test-build --target sub/bar.o
cmake --build test-build --target bar.o
cmake --build test-build --target bar
I get these kinds of error messages gmake: *** No rule to make target 'sub/bar.o'. Stop.
I know it's possible to build the library, but in reality our library is quite large and I would like to focus on one file at the time.

Unable to use specific compiler in cmake created CodeBlocks project

I have various projects that I need to compile them with different compilers.
So, what I need is an IDE that lets easily allow me to choose/change a target and compile projects for that target.
Another need is to use cmake.
I am now trying CodeBlocks in windows. First I try to add a compiler:
I have set:
Settings->Toolchain executables->Compiler's installation directory->Program Files
Then I create CodeBlocks project with cmake -G "CodeBlocks - MinGW Makefiles"
I open the project in CodeBlocks that is generated by cmake.
I chose compiler in Project Settings.
I build.
Then I discover that compiler in Project Settings is totally ignored! Because it is used the one in CMakeCache.
Thus, I write a script that first set CC and CXX, then run cmake.
With this way I see that CMakeCache has the compiler that I want.
Then I build the project in CodeBlocks.
Now, for g++.exe, the correct compiler is used. However, CodeBlocks insists and insists again to use default MinGW compiler (which is in path) for mingw32-make.exe
Here is the last build output, where D:/Qt/Qt5.4.1/Tools/mingw491_32/bin is default and C:\mingw_x86_64\release7.1.0-posix-dwarf-rt_v5-rev2.7\bin is the correct one.
-------------- Build: 32bit in deneme21 (compiler: MinGW GCC Compiler 32bit)---------------
Checking if target is up-to-date: mingw32-make.exe -q -f Makefile 32bit
Running command: D:/Qt/Qt5.4.1/Tools/mingw491_32/bin/mingw32-make.exe -f "D:/Qt_ws/deneme/deneme31/Makefile" VERBOSE=1 install/strip
C:\CMake3.10.2\win32\bin\cmake.exe -HD:\Qt_ws\deneme\deneme31 -BD:\Qt_ws\deneme\deneme31 --check-build-system CMakeFiles\Makefile.cmake 0
C:\CMake3.10.2\win32\bin\cmake.exe -E cmake_progress_start D:\Qt_ws\deneme\deneme31\CMakeFiles D:\Qt_ws\deneme\deneme31\CMakeFiles\progress.marks
D:/Qt/Qt5.4.1/Tools/mingw491_32/bin/mingw32-make.exe -f CMakeFiles\Makefile2 all
mingw32-make.exe[1]: Entering directory 'D:/Qt_ws/deneme/deneme31'
D:/Qt/Qt5.4.1/Tools/mingw491_32/bin/mingw32-make.exe -f CMakeFiles\deneme21.dir\build.make CMakeFiles/deneme21.dir/depend
mingw32-make.exe[2]: Entering directory 'D:/Qt_ws/deneme/deneme31'
C:\CMake3.10.2\win32\bin\cmake.exe -E cmake_depends "MinGW Makefiles" D:\Qt_ws\deneme\deneme31 D:\Qt_ws\deneme\deneme31 D:\Qt_ws\deneme\deneme31 D:\Qt_ws\deneme\deneme31 D:\Qt_ws\deneme\deneme31\CMakeFiles\deneme21.dir\DependInfo.cmake --color=
mingw32-make.exe[2]: Leaving directory 'D:/Qt_ws/deneme/deneme31'
D:/Qt/Qt5.4.1/Tools/mingw491_32/bin/mingw32-make.exe -f CMakeFiles\deneme21.dir\build.make CMakeFiles/deneme21.dir/build
mingw32-make.exe[2]: Entering directory 'D:/Qt_ws/deneme/deneme31'
[ 50%] Building CXX object CMakeFiles/deneme21.dir/src/foo.cpp.obj
C:\mingw_x86_64\release7.1.0-posix-dwarf-rt_v5-rev2.7\bin\g++.exe #CMakeFiles/deneme21.dir/includes_CXX.rsp -m32 -o CMakeFiles\deneme21.dir\src\foo.cpp.obj -c D:\Qt_ws\deneme\deneme31\src\foo.cpp
[100%] Linking CXX static library libdeneme21.a
C:\CMake3.10.2\win32\bin\cmake.exe -P CMakeFiles\deneme21.dir\cmake_clean_target.cmake
C:\CMake3.10.2\win32\bin\cmake.exe -E cmake_link_script CMakeFiles\deneme21.dir\link.txt --verbose=1
C:\mingw_x86_64\release7.1.0-posix-dwarf-rt_v5-rev2.7\bin\ar.exe qc libdeneme21.a CMakeFiles/deneme21.dir/src/foo.cpp.obj
C:\mingw_x86_64\release7.1.0-posix-dwarf-rt_v5-rev2.7\bin\ranlib.exe libdeneme21.a
mingw32-make.exe[2]: Leaving directory 'D:/Qt_ws/deneme/deneme31'
[100%] Built target deneme21
mingw32-make.exe[1]: Leaving directory 'D:/Qt_ws/deneme/deneme31'
C:\CMake3.10.2\win32\bin\cmake.exe -E cmake_progress_start D:\Qt_ws\deneme\deneme31\CMakeFiles 0
D:/Qt/Qt5.4.1/Tools/mingw491_32/bin/mingw32-make.exe -f CMakeFiles\Makefile2 preinstall
How can I make CodeBlocks use the compiler that I want in cmake created project?

How to instruct CMake to use the build architecture compiler

When using CMake for cross compiling, one generally specifies a toolchain file via the CMAKE_TOOLCHAIN_FILE option. In GNU terminology, one can specify the host architecture toolset using this file. However, one can generally not expect to be able to execute anything built with this toolchain. So often enough, some build tools need to be compiled for the build architecture.
Consider the following setup. I have two source files genfoo.c and bar.c. During build, genfoo.c needs to be compiled and run. Its output needs to be written to foo.h. Then I can compile bar.c, which #include "foo.h". Since CMake defaults to using the host architecture toolchain, the instructions for bar.c are easy. But how do I tell it to use the build architecture toolchain for compiling genfoo.c? Simply saying add_executable(genfoo genfoo.c) will result in using the wrong compiler.
CMake can only handle one compiler at a time. So - if you don't go the long way to set up the other compiler as a new language - you will end up with two configuration cycles.
I see the following approaches to automate this process:
Taking the example "CMake Cross Compiling - Using executables in the build created during the build?" from the CMake pages as a starting point I'll get:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# When crosscompiling import the executable targets
if (CMAKE_CROSSCOMPILING)
set(IMPORT_PATH "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file path from a native build")
file(TO_CMAKE_PATH "${IMPORT_PATH}" IMPORT_PATH_CMAKE)
include(${IMPORT_PATH_CMAKE}/genfooTargets.cmake)
# Then use the target name as COMMAND, CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
endif()
# Only build the generator if not crosscompiling
if (NOT CMAKE_CROSSCOMPILING)
add_executable(genfoo genfoo.cpp)
export(TARGETS genfoo FILE "${CMAKE_CURRENT_BINARY_DIR}/genfooTargets.cmake")
endif()
Then using a script like:
build.sh
#!/bin/bash
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ..
fi
cmake --build hostBuild
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DIMPORT_PATH=${PWD}/hostBuild -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
cmake --build crossBuild
I'll get the desired results by calling ./build.sh.
Splitting the CMakeLists.txt and maybe even replace the export()/include() with something where I know the output path of my build tools e.g. by using CMAKE_RUNTIME_OUTPUT_DIRECTORY would simplify things:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# Then use the target name as COMMAND. CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
buildTools/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(BuildTools)
add_executable(genfoo genfoo.cpp)
build.sh
#!/bin/bash
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ../buildTools -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${PWD}/crossBuild
fi
cmake --build hostBuild
cmake --build crossBuild
References
Making a CMake library accessible by other CMake packages automatically
CMake build multiple targets in different build directories
How do I make CMake output into a 'bin' dir?
It is possible to do that completely within CMake.
The trick is to run a separate CMake configuring stage within its own space, silently dismissing every crosscompiling setting and using the host's default toolchain, then import the generated outputs into it's parent, crosscompiling build.
First part:
set(host_tools_list wxrc generate_foo)
if(CMAKE_CROSSCOMPILING)
# Pawn off the creation of the host utilities into its own dedicated space
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools)
file(TO_NATIVE_PATH ${CMAKE_COMMAND} native_cmake_command)
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} native_cmake_current_source_dir)
execute_process(
COMMAND "${native_cmake_command}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "${native_cmake_current_source_dir}"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
add_custom_target(host_tools
COMMAND ${CMAKE_COMMAND} --build . --target host_tools --config $<CONFIG>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
include(${CMAKE_CURRENT_BINARY_DIR}/host_tools/host_tools.cmake)
foreach(tgt IN ITEMS ${host_tools_list})
add_dependencies(host${tgt} host_tools)
endforeach()
else()
# Add an empty target, host tools are built inplace
add_custom_target(host_tools
DEPENDS ${host_tools_list}
)
endif()
... then you add the usual add_executable and whatever ...
At the end:
if(NOT CMAKE_CROSSCOMPILING)
foreach(tgt IN ITEMS ${host_tools_list})
add_executable(host${tgt} ALIAS ${tgt})
endforeach()
export(TARGETS ${host_tools_list} NAMESPACE host FILE host_tools.cmake)
endif()
When it crosscompiles, it pawns off the creation of the host-run tools into its own dedicated space, and imports the targets as "hostwxrc" and "hostgenerate_foo", with a dependency on generating the host_tools themselves .
When it doesn't crosscompile, it builds wxrc and generate_foo as-is, and aliases them to hostwxrc and hostgenerate_foo.
After this, when you use $<TARGET_FILE:wxrc>, you refer to the wxrc built for the target platform, and $<TARGET_FILE:hostwxrc> refers to the wxrc built for the host platform, regardless whether they are the same or not.