Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cmake - targeting multiple architectures at once without manual cleaning between builds

I am developing a cross-platform C++ library for Android and iOS and I am using cmake to prepare build scripts.

A project structure looks something like:

somelib
|
├─ .gitignore
|
├── src
│   └── CMakeLists.txt
│   └── Doxyfile.in
|   └── include (Public headers)
│       └── somelib
│           └── somelib.hpp
│   └── somelib
│       └── CMakeLists.txt
│       └── somelib.cpp
│       └── ....hpp, ....cpp
│       └── test
│           └── test_classname.cpp
│   └── libs (source of 3rd party libs)
│       └── 3rd_party_lib_1
│           └── CMakeLists.txt
│           └── ...
│       └── ...
│           └── CMakeLists.txt
│           └── ...
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
├── toolchains
│   └── andoid
│       └── android.toolchain.cmake
│       └── ...
│   └── ios
│       └── ios.toolchain.cmake
│       └── ...
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── build
│   └── build.sh
│   └── Doxyfile
│   └── ...
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
├── dist (distribute)
│   └── docs
│       └── index.html
│       └── ...
|   └── include (Public headers)
│       └── somelib.hpp
│   └── local
|       └── somelibtest (executable tests)
│   └── android
│       └── Debug
│           └── armeabi
│           └── armeabi-v7a
│           └── ...
│       └── Release
│           └── armeabi
│           └── armeabi-v7a
│           └── ...
│   └── ios
│       └── Debug
│           └── armv
│           └── armv7
│           └── ...
│       └── Release
│           └── armv
│           └── armv7
│           └── ...
|

I am running cmake from ./build/ path by executing build.sh which in case of building for android, looks something like this:

build.sh:

...

TARGETS="armeabi-v7a armeabi x86 mips arm64-v8a mips64"

mkdir -p "$BUILD_PATH"

for TARGET in $TARGETS
do

    cmake -DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_TOOLCHAIN} -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DANDROID_ABI=${TARGET} -DPROJ_HOME=${PROJ_HOME} ../src

    make -j32

  done

fi
...

If I am building for one particular architecture, for example setting TARGETS to "arm64-v8a" only, the library builts well. In case if I want to build a library for multiple architectures at once then it does not work well since cmake prepares build script specifically for each platform/architecture. I get linker errors such as "incompatible target" durring the build.

What is the best practice to build libraries targeting multiple platforms and multi-architecture?

How can I avoid cleaning build script files before preparing to build for another architecture?

Thank you for any suggestions!


PS: Here are some lines from main src/CmakeLists.txt file:

cmake_minimum_required(VERSION 3.6.0 FATAL_ERROR)

include(GNUInstallDirs)

# Set default build type
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Release")
endif()

## Output directories

if (IOS)
  set(REL_OUTPUT_DIR "ios/${CMAKE_BUILD_TYPE}/${IOS_ARCH}")
elseif (ANDROID)
  set(REL_OUTPUT_DIR "android/${CMAKE_BUILD_TYPE}/${ANDROID_ABI}")
else()
  set(REL_OUTPUT_DIR "local")
endif()
set(OUTPUT_DIR ${CMAKE_BINARY_DIR}/../dist/${REL_OUTPUT_DIR})
set(DESTDIR ${CMAKE_BINARY_DIR}/../dist/${REL_OUTPUT_DIR})

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${OUTPUT_DIR}") # Static libraries
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OUTPUT_DIR}") # Dynamic libraries
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OUTPUT_DIR}") # Executables

# Include libraries
add_subdirectory(libs/3rd_party_lib_1)
add_subdirectory(libs/3rd_party_lib_n)
like image 837
Boštjan Biber Avatar asked Nov 06 '17 21:11

Boštjan Biber


1 Answers

An option, as I eluded to in the comments, is to use one build directory per target architecture

...

TARGETS="armeabi-v7a armeabi x86 mips arm64-v8a mips64"

for TARGET in ${TARGETS}
do    
    # create one build dir per target architecture
    mkdir -p ${BUILD_PATH}/${TARGET}
    cd ${BUILD_PATH}/${TARGET}

    cmake -DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_TOOLCHAIN} -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DANDROID_ABI=${TARGET} -DPROJ_HOME=${PROJ_HOME} ../../src

    make -j32

    cd -    
done

...

This will result in a tree looking somewhat like the following

project/
+--- src/
+--- build/
     +--- armeabi-v7a/
     +--- armeabi/
     +--- x86/
     +--- mips/
     +--- arm64-v8a/
     +--- mips64/
like image 96
Steve Lorimer Avatar answered Oct 27 '22 07:10

Steve Lorimer