- Как компилировать на Linux и на Windows одновременно, используя CMake?
- Building CMake for Windows from source by bootstrapping on Linux, then cross-compiling
- 1 Answer 1
- Building CMake v3.12.3 for Windows via bootstrapped Linux CMake from Git
- Our build system
- Install prerequisites
- Getting the source
- Building CMake for Linux (optional)
- Bootstrapping a Linux CMake
- Preparations for the Windows build
- Building the Windows version of CMake
- The results
- Cross-platform build under Windows targeting Linux using CMake
Как компилировать на Linux и на Windows одновременно, используя CMake?
Я пишу всё с Linux-а, и все проекты, соответственно, собираются исключительно под Linux.
Недавно я нашёл, что с помощью MinGW можно компелировать с Линукса проекты на винду. Попробовал «Hello, World!» — проверил — получилось. Это меня обрадовало. Попробовал немножечко переделать один из своих давних проектов, который использовал несколько сторонних библиотек, и вот тут начались трудности. Очевидно, что для Windows пойдут только соответствующие библиотеки. Скачал, вроде всё правильно настроил в CMake-е, но. Любимый undefined reference встретил меня с улыбкой. Мой CMake:
cmake_minimum_required(VERSION 3.10) project(DiSqProj) set(CMAKE_CXX_STANDARD 17) if (false) # Unix message("Building project for Unix.") set(LIBS -lGL -lGLEW -lglfw -lsfml-graphics -lsfml-window -lsfml-system) elseif(true) # Win64 message("Building project for Win64.") set(WIN_LIBS_DIR /home/prunkles/Dev/CLionProjects/WinLibs) set(INCLUDE_DIRS PUBLIC $/glew-2.1.0/include # GLEW include PUBLIC $/glfw-3.2.1/include # GLFW include PUBLIC $/SFML-2.5.0/include # SFML include PUBLIC $/glm/include # GLM include ) set(LINK_DIRS $/glew-2.1.0/lib/Release/x64 # GLEW lib $/glfw-3.2.1/lib-mingw-w64 # GLFW lib $/SFML-2.5.0/lib # SFML lib ) set(LIBS glew32s glfw3 sfml-graphics sfml-window sfml-system ) endif() link_directories($) add_executable($ main.cpp DiamondSquare.cpp DiamondSquare.h rand-adv.h inWin3D.cpp inWin2D.cpp inFiles.cpp ViewTypes.h genImageFromMap.cpp genImageFromMap.h Camera.cpp Camera.h GLLoadShaders.h) target_include_directories($ $) target_link_libraries($ $)
А те сторонние библиотеки случайно не для Microsoft Visual Studio собраны? Там другие правила декорирования (mangling) экспортируемых C++-имён, отличные от таковых у GCC.
@Arhad Могу ли я скачать исходники и собрать библиотеку сам? В таком случае, это уже точно нужно делать с Windows, да?
Если вы скачиваете исходники, собирать их надо тем же инструментарием, что и вашу программу. Тогда, во-первых, автоматом сойдутся соглашения вызовов и правила декорирования, а во-вторых, сформируется зависимость от одной и той же runtime-библиотеки C++. То есть если вы собираете под Linux-овым портом MinGW, то и библиотеку надо собирать там же.
Building CMake for Windows from source by bootstrapping on Linux, then cross-compiling
CMake is a build system, but Windows binaries provided by the official project are neither code-signed nor signed with PGP. So if you are like me and distrust the prebuilt binaries you may find the answer below useful. I ran into a number of issues on the path to my CMake build for Windows, so the answer below may spare you some trial and error or generally repeating some steps. Last time I checked the MinGW distribution was not signed either and aside from that it appears to be rather sluggish compared to GCC on Linux.
1 Answer 1
Note: revision 2 explains the steps for CMake 3.3.0, in case you happen to be interested in an older version of CMake.
In order to build CMake, we need a working CMake of some kind. Catch 22, right, since we can’t trust the binaries provided on the official download page.
This answer describes how to build a Windows (32-bit, i.e. x86) build for CMake from Linux with a Linux CMake bootstrapped from the source code in order to bootstrap the Windows one.
Building CMake v3.12.3 for Windows via bootstrapped Linux CMake from Git
Our build system
In my case I chose Ubuntu 18.04 as the build system for bootstrapping a Windows CMake.
I assume that the meta-package build-essential is already installed, if not go ahead and install it. It contains most of the build tools we’ll need.
If you don’t have qt4-qmake installed you will get the following lines at the end of the output when invoking ./bootstrap . This is not fatal for the first step, apparently in the same way that a missing curses library is non-fatal.
qmake: could not exec '/usr/lib/x86_64-linux-gnu/qt4/bin/qmake': No such file or directory qmake: could not exec '/usr/lib/x86_64-linux-gnu/qt4/bin/qmake': No such file or directory
The cross-compile for Windows 32-bit will, however, fail with those exact two lines.
Install prerequisites
Note (again): it is assumed that build-essential is installed. So we’ll want to install five packages and their dependencies:
- mingw-w64 (required as a cross-compiler to target Windows)
- git (required to fetch the source from Kitware)
- qt4-qmake and qt4-default (required during the cross-compile)
- nsis (required if we want to run make package after the cross-compile)
Install these packages as follows, adjust to your package manager if you are not on Ubuntu 18.04:
sudo apt-get --no-install-recommends install mingw-w64 git qt4-qmake qt4-default nsis
Getting the source
I’m assuming that you are inside of your home folder, but it’s not mandatory. Make sure to adjust path names accordingly, though.
git clone https://gitlab.kitware.com/cmake/cmake.git
This should clone the repository into a subfolder cmake .
Building CMake for Linux (optional)
NB: Feel free to skip this step if your package manager provides a recent enough version of CMake that is suitable for the subsequent steps.
and check out the tag for the desired version (list the tags with git tag -l ):
Bootstrapping a Linux CMake
Follow the steps outlined on Installing CMake:
(assuming you are still in the subfolder into which you changed in the previous section).
The process will hopefully finish successfully with the last two lines being something like:
--------------------------------------------- CMake has bootstrapped. Now run make.
So follow the instruction and invoke make :
This should now build the actual Linux CMake which we will then use to build the Windows one.
After the make process finished, you should have the executables that comprise CMake under bin , try the cmake binary to see whether it works:
$ bin/cmake --version cmake version 3.12.3 CMake suite maintained and supported by Kitware (kitware.com/cmake).
Preparations for the Windows build
Now change one folder up again:
and clone the Git repository from before into a new directory named cmake-windows :
git clone cmake cmake-windows
then change into that directory and check out the same tag you picked before for Linux already (or the latest stable or whatever you please, really):
cd cmake-windows git checkout v3.12.3
Building the Windows version of CMake
If you’re curious, check out revision 2. It details an issue I ran into the first time around. Basically the built binaries were not able to run on Windows, which required that they be statically linked against certain libraries. These instructions already take care of that for you, though!
Still inside the cmake-windows we will now build the Windows version of CMake. For this we need to create a «toolchain file» ~/mingw-w64-toolchain.cmake as outlined here. Create a file with the following contents:
# the name of the target operating system SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc-posix) SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++-posix) SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) # here is the target environment located SET(CMAKE_FIND_ROOT_PATH /usr/share/mingw-w64 /usr/i686-w64-mingw32/ ) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) SET(CMAKE_EXE_LINKER_FLAGS "$ -static-libstdc++ -static-libgcc -static -lwinpthread" )
and then invoke the Linux cmake binary we built before (adjust the path if you didn’t use your home folder as base folder):
~/cmake/bin/cmake -DCMAKE_TOOLCHAIN_FILE=~/mingw-w64-toolchain.cmake -DKWSYS_LFS_WORKS=0
This should create the Makefile which we can then use to build the Windows version.
followed by the following command to create a setup package:
The results
The result should be (with the variable expanded):
CPack: - package: $HOME/cmake/cmake-3.12.3-win32-x86.exe generated.
You should now have a CMake build which only depends on system libraries.
Last but not least copy that trusted build of CMake for Windows onto your Windows machine and use it however you please.
Including, perhaps, code-signing and making it available to the world or even bootstrapping a «native» Visual Studio build of CMake for Windows?!
Cross-platform build under Windows targeting Linux using CMake
I am developing a software in C++ on windows 32-bit (using MSVC++), but since I want to be able to use my software on every platform, I have decided to use CMake as my build generator. Therefore, I am still just a beginner in CMake. From the CMake tutorials, I understand that in order to cross compile codes, first a toolchain simulating the target platform should be installed on the host platform. Then using the appropriate target-platform C and C++ compilers provided by this toolchain, CMake would be able to generate makefiles etc. Now, I want to build my code for Linux platform(GNU/Linux) on a Win32 platform. I tried doing the above procedure using CMake combined with Cygwin and using gcc and g++ as compilers. It built fine, created makefiles, and when I issued «make» in Cygwin terminal, the generated makefiles were «made». Now I have got an executable which I was hoping would run on Linux platform. But on Linux I get the error: bash cannot execute binary file. Using command file executablename, I realized the executable which is made by the above procedure is of type PE32 which is only for Windows. Now my question is: Is my understanding of cross-platform build procedure using cmake correct?Or should I just use another Linux toolchain under windows to get a Linux ELF executable? What toolchains come to your mind which would give me what I want? Many thanks Setareh
I don’t know about cmake, but qmake has «build profiles» for different platforms. Maybe, you should search for «target platform» option in cmake docs, or something like that.
@IvanKolmycheck Thank you, do you still need to have a toolchain on your host platform to build for a different target platform or do you simply specify the «build profile» in qmake and qmake generates appropriate makefiles for the target platform? I mean, can the compilers listed in your mkspecs be used directly through qmake or is some other procedure(like a third party toolchain) also involved?
@user2470116 Qmake automaticaly generates the makefiles for toolchain, but it still needs to be installed via your distro package manager.