Cmake learning record (nine)--use Cmake to cross compile Android .so library

I. Introduction

At present, it is relatively simple to use Android Studio to compile .so for Android, but sometimes you need to create an Android project for Android Studio. Here, it is recorded that you can use Cmake and C++ development tools Clion without Android Studio (or other development tools. These development tools are not the same as Android Studio, any tool will do).
In fact, there is a simpler way to compile .so. For example, you can use cmake to compile the c++ project directly under the linux environment, and the .so library appears at this time. But if the development environment is Mac or Windows, dylib or exe files will be generated, which are not the files we want, so we need to use cross-compilation technology.
Cmake provides two ways to compile Android .so files: NDK or cross toolchain . Since I am engaged in Android development, there are ready-made NDK dependencies, and the cross-compilation chain needs to be downloaded. So I use NDK to compile, but it is probably possible to modify it according to this. Later, when there is time, we will record the compilation method using the cross toolchain.
The project is messy, and I will organize it later.
However, no matter which way you use NDK or cross tool chain, you need to associate with NDK, and there will be no problem of compiling .so without NDK

2. Relevant code compiled using NDK

The development tool is CLion. It should be noted that both Android Studio and CLion use the ninja build system. If you use other build systems, you need to modify it, but the code in the article already has this code, and you can just change the path at that time. The overall project structure is as
follows
insert image description here
: The core code is:
It should be noted that the set part of the code needs to be written project(untitled VERSION 1.0)before the function call

# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21) # API level
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
set(CMAKE_ANDROID_NDK /Users/c/Documents/sdk/android/ndk/25.1.8937393)
#set(CMAKE_TOOLCHAIN_FILE /Users/c/Documents/sdk/android/ndk/25.1.8937393/build/cmake/android.toolchain.cmake)
set(CMAKE_MAKE_PROGRAM /Users/c/Documents/sdk/android/cmake/3.22.1/bin/ninja)
#set(CMAKE_ANDROID_STL_TYPE gnustl_static) # 需要注意的是NDK不支持这个属性,可能是NDK版本原因,所以使用c++_shared,
set(CMAKE_ANDROID_STL_TYPE c++_shared)
set(CMAKE_EXPORT_COMPILE_COMMANDS NO)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

aux_source_directory(. SRC_LIST) #把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST
#ADD_EXECUTABLE(hello ${SRC_LIST}) #生成应用程序 hello (在windows下会自动生成hello.exe)

# 将相关文件添加到SqrtLibrary库 ,最终编译成共享库 .so
add_library(SqrtLibrary SHARED
        ${SRC_LIST}
        )

CMakeLists.txt

cmake_minimum_required(VERSION 3.23) # 这是Cmake版本

#======这一段来自Android开发者平台:https://developer.android.google.cn/ndk/guides/cmake?hl=zh-cn#using_prebuilt_libraries 
#-DCMAKE_FIND_ROOT_PATH=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/prefab/armeabi-v7a/prefab
#-DCMAKE_BUILD_TYPE=Debug
#-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk/22.1.7171670/build/cmake/android.toolchain.cmake
#-DANDROID_ABI=armeabi-v7a
#-DANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
#-DANDROID_PLATFORM=android-23
#-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
#-DCMAKE_ANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
#-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
#-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
#-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
#-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
#-DCMAKE_SYSTEM_NAME=Android
#-DCMAKE_SYSTEM_VERSION=23

#====== end ======


# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21) # API level
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
set(CMAKE_ANDROID_NDK /Users/c/Documents/sdk/android/ndk/25.1.8937393)
set(CMAKE_MAKE_PROGRAM /Users/c/Documents/sdk/android/cmake/3.22.1/bin/ninja)
#set(CMAKE_ANDROID_STL_TYPE gnustl_static) # 需要注意的是NDK不支持这个属性,可能是NDK版本原因,所以使用c++_shared,
set(CMAKE_ANDROID_STL_TYPE c++_shared)
set(CMAKE_EXPORT_COMPILE_COMMANDS NO)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

project(untitled VERSION 1.0)

add_subdirectory(libscanner)
configure_file(square.h.in square.h)

# specify the C++ standard
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)


# 通过BUILD_SHARED_LIBS 创建共享库,后面值需要设置为ON,
# 这个属性写到这里,如果libscanner使用这个值的话有时候会报找不到的错误,如果经过反复Build后无法解决,将该属性写到相关的libscanner的CMakeLists.txt。但是这样的话最终rebuld后只会生成libscanner的.so。不过这也是预想的情况本身顶层目录也没有要求生成.so文件
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)

add_executable(untitled square_main.cpp)

target_link_libraries(untitled PUBLIC scanner tutorial_compiler_flags)
target_include_directories(untitled PUBLIC
        "${PROJECT_BINARY_DIR}"
        "${PROJECT_SOURCE_DIR}/libscanner"
        )

# 打印日志
message("---PROJECT_BINARY_DIR--${PROJECT_BINARY_DIR}")
message("---PROJECT_SOURCE_DIR--${PROJECT_SOURCE_DIR}")
message("---libscanner头文件--${PROJECT_SOURCE_DIR}/libscanner")

libscanner/CMakeLists.txt

add_library(scanner scanner.cpp) # 默认编译成静态库
# state that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
target_include_directories(scanner
        INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
        )

#add_executable(MakeTable scanner.cpp)
#target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
aux_source_directory(. SRC_LIST) #把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST
#ADD_EXECUTABLE(hello ${SRC_LIST}) #生成应用程序 hello (在windows下会自动生成hello.exe)


# 将相关文件添加到SqrtLibrary库
add_library(SqrtLibrary SHARED
       ${SRC_LIST}
        )


# 文件应该去哪个路径下面查找
target_include_directories(SqrtLibrary PRIVATE
        ${CMAKE_CURRENT_BINARY_DIR}
        )

# 将tutorial_compiler_flags库链接到SqrtLibrary
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)

# 将SqrtLibrary库链接到libscanner
target_link_libraries(scanner PRIVATE SqrtLibrary)

# 将tutorial_compiler_flags库链接到libscanner
target_link_libraries(scanner PUBLIC tutorial_compiler_flags)


message("YM--->${BUILD_SHARED_LIBS}")

# state that SqrtLibrary need PIC when the default is shared libraries
set_target_properties(SqrtLibrary PROPERTIES
        POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
        )

After re-rebuilding after writing, you can find the generated .so library in the build folder

Fourth, use the cross tool chain to compile

If you use a cross-tool chain, compiling only needs to change one line of code compared to the above method. Due to the changes after the new version of NDK r-19, it will be easier to use. Just specify the CMAKE_TOOLCHAIN_FILE property

#set(CMAKE_ANDROID_NDK /Users/c/Documents/sdk/android/ndk/25.1.8937393)
set(CMAKE_TOOLCHAIN_FILE /Users/c/Documents/sdk/android/ndk/25.1.8937393/build/cmake/android.toolchain.cmake)

4. Reference link

  1. Introduction to CMake on the Android official website
  2. In-depth understanding of using CMake to compile NDK programs
  3. cmake-toolchains(7)
  4. android/ndk-samples
  5. CMAKE builds android compilation, packaging and release environment under Linux
  6. Common libraries for android cross compilation (cmake
  7. 10. Notes on NDK cross compilation
  8. cmake: add_library detailed explanation

Guess you like

Origin blog.csdn.net/Mr_Tony/article/details/130956210