c++buildcross-build

Metabuild tool to handle multiple cross-builds simultaneously


I have a mid-sized C++ project that runs on Linux, Windows and Mac OS X, both 32- and 64-bit. On some platforms it has more than one variant (e.g. Gtk-2 and Gtk-3 variants on Linux). Being mostly a hobby programmer, I don't have resources for dedicated build machines for each platform. So I installed cross-compilers for each one so that all building takes place on my Linux box.

I want to be able to build all ten or so variants with a single command. Right now I achieve this with a quick and dirty Python script that creates a makefile (actually I switched to ninja recently but it's not very relevant I guess). It creates Windows installers, Debian packages and whatnot for each variant. But I want a cleaner solution because my script is not gonna scale well as the project grows.

So my question is: What metabuild tools are able to create a single Makefile (or similar, like a ninja build file) that can handle multiple toolkits (cross-compilers) and custom commands (to create installers etc.)?

I tried CMake (and some others) but it's not obvious to me how to work with multiple toolkits. Most tools seem to create one Makefile per configuration.

Edit: Now, this answer claims that it's not possible. I don't understand why. If I can do it with my 15 minutes python script, I feel like there must be a tool able to do it for me.


Solution

  • You can get this behaviour with CMake, using Toolchains and ExternalProject. Different makefiles will still be created behind the scenes, but that doesn't affect the user or the scalability of the project.

    First, you will need to turn your project into a CMake project, with all the ifs and elses needed to build on all the different platforms in the CMakeLists.txt file.

    You can create a set of toolchain files e.g. named <target>.toolchain and your cross build CMakeLists.txt where all the magic is done:

    cmake_minimum_required(VERSION 3.0.2)
    project(cross-build-project)
    include(ExternalProject)
    
    set(project_dir <path to your CMake project>)
    set(targets_dir ${CMAKE_SOURCE_DIR}/targets)
    
    function(add_target target_toolchain)
      get_filename_component(target_name ${target_toolchain} NAME_WE)
      ExternalProject_Add(
          ${target_name}
          PREFIX ${targets_dir}/${target_name}
          SOURCE_DIR ${project_dir}
          CMAKE_ARGS -DTOOLCHAIN_FILE=${target_toolchain}
          BINARY_DIR ${targets_dir}/${target_name}
        )
    endfunction(add_target)
    
    file(GLOB toolchains "*.toolchain")
    foreach(toolchain ${toolchains})
      add_target(${toolchain})
    endforeach()
    

    This should provide a platform that can be adjusted to your specific needs and scale well with the project.