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)
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/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With