I tried with this example, but nothing happens:
cmake_minimum_required(VERSION 3.8)
project(cmake_simulator)
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21)
set(CMAKE_ANDROID_ARCH_ABI x86)
set(CMAKE_ANDROID_NDK /home/icarolima/Android/Sdk/ndk/21.3.6528147)
set(CMAKE_ANDROID_STL_TYPE gnustl_static)
set(CMAKE_TOOLCHAIN_FILE /home/icarolima/Android/Sdk/ndk/21.3.6528147/build/cmake/android.toolchain.cmake)
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
if (NOT verilator_FOUND)
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
endif()
# Create a new executable target that will contain all your sources
add_library(simulator SHARED simulator.cpp)
# Add the Verilated circuit to the target
verilate(simulator
INCLUDE_DIRS "."
SOURCES top.sv
VERILATOR_ARGS -Wno-CASEINCOMPLETE -Wno-WIDTH -Wno-COMBDLY -cc +1800-2012ext+sv)
For example, if I change the CMAKE_ANDROID_ARCH_ABI to anything else, nothing happens. It is like CMake is ignoring the NDK part of the code.
But If I change the project to another location, different things happen:
cmake_minimum_required(VERSION 3.8)
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21)
set(CMAKE_ANDROID_ARCH_ABI x86)
set(CMAKE_ANDROID_NDK /home/icarolima/Android/Sdk/ndk/21.3.6528147)
set(CMAKE_ANDROID_STL_TYPE gnustl_static)
project(cmake_simulator)
set(CMAKE_TOOLCHAIN_FILE /home/icarolima/Android/Sdk/ndk/21.3.6528147/build/cmake/android.toolchain.cmake)
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
if (NOT verilator_FOUND)
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
endif()
# Create a new executable target that will contain all your sources
add_library(simulator SHARED simulator.cpp)
# Add the Verilated circuit to the target
verilate(simulator
INCLUDE_DIRS "."
SOURCES top.sv
VERILATOR_ARGS -Wno-CASEINCOMPLETE -Wno-WIDTH -Wno-COMBDLY -cc +1800-2012ext+sv)
The error:
CMake Error at /home/icarolima/Android/Sdk/cmake/3.10.2.4988404/share/cmake-3.10/Modules/Platform/Android/Determine-Compiler-NDK.cmake:97 (message):
Android: No toolchain for ABI 'x86' found in the NDK:
/home/icarolima/Android/Sdk/ndk/21.3.6528147
I have no experience with CMake, I think that the problem is the order of the things. Can anyone help me?
Setting all of these variables (such as CMAKE_SYSTEM_NAME, CMAKE_SYSTEM_VERSION, CMAKE_ANDROID_ARCH_ABI, etc.) should happen in the toolchain file. You may certainly experience some nasty CMake behavior by putting these in the CMakeLists.txt file itself. There is even a sample toolchain file in the CMake documentation you linked here.
Also, the CMAKE_TOOLCHAIN_FILE variable should be set on the command line when you call cmake, not in the CMake file itself. This reduces your CMakeLists.txt file to something like this:
cmake_minimum_required(VERSION 3.8)
project(cmake_simulator)
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
if (NOT verilator_FOUND)
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
endif()
# Create a new executable target that will contain all your sources
add_library(simulator SHARED simulator.cpp)
# Add the Verilated circuit to the target
verilate(simulator
INCLUDE_DIRS "."
SOURCES top.sv
VERILATOR_ARGS -Wno-CASEINCOMPLETE -Wno-WIDTH -Wno-COMBDLY -cc +1800-2012ext+sv)
Then, you should call cmake, specifying the toolchain file to use, like this:
cmake -DCMAKE_TOOLCHAIN_FILE=/home/icarolima/Android/Sdk/ndk/21.3.6528147/build/cmake/android.toolchain.cmake ..
So, just to clarify, the way I solved it can be seen here: Dockerfile, and here: sandbox_template.
Thanks for the answers #squareskittles!
Related
I am trying to use Protocol Buffers in C++ under Android (x86, x86_64, armeabi-v7a, arm64-v8a). Using these build scripts, I have been able to generate libprotobuf.a static libraries for the different architectures.
However, I am struggling to make the connection between the static libraries and the test_spec.pb.cc and test_spec.pb.h files that I generated with my system's global protobuf compiler of the same version (3.19.2).
What I have tried
I have tried setting both the Protobuf_LIBRARY and Protobuf_LIBRARIES to the path to libprotobuf.a
I have tried setting Protobuf_INCLUDE_DIRS and Protobuf_INCLUDE_DIR to the include directory I generated running the extract_includes.bat.in script in protobuf's cmake folder
I have tried finding protobuf using find_package( Protobuf REQUIRED ) and find_package( Protobuf REQUIRED HINTS _path_to_dir_containing_lib_and_include_)
I have tried setting Protobuf_SRC_ROOT_FOLDER to a directory containing libprotobuf.a and the include folder
This is my current CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
set (CMAKE_VERBOSE_MAKEFILE ON)
set (CMAKE_CXX_STANDARD 11)
set(CMAKE_PREFIX_PATH
${CMAKE_PREFIX_PATH}
${CMAKE_PREFIX_PATH}/../cpp
)
ADD_LIBRARY(protobuf STATIC IMPORTED)
SET_TARGET_PROPERTIES(protobuf PROPERTIES IMPORTED_LOCATION ../cpp/libs/${ANDROID_ARCH}/google/protobuf/libprotobuf.a)
INCLUDE(FindProtobuf)
SET(Protobuf_USE_STATIC_LIBS ON)
SET(Protobuf_SRC_ROOT_FOLDER ../cpp)
SET(Protobuf_LIBRARIES protobuf)
SET(Protobuf_INCLUDE_DIR ../cpp/include/google/protobuf)
FIND_PACKAGE(Protobuf REQUIRED)
ADD_LIBRARY(cpp
SHARED
../cpp/rn-etsi-parser.cpp
cpp-adapter.cpp
)
# Specifies a path to native header files.
INCLUDE_DIRECTORIES(
../cpp
)
And this is the current error I get when I run it:
CMake Error at CMakeLists.txt:18 (FIND_PACKAGE):
Could not find a package configuration file provided by "Protobuf" with any
of the following names:
ProtobufConfig.cmake
protobuf-config.cmake
Add the installation prefix of "Protobuf" to CMAKE_PREFIX_PATH or set
"Protobuf_DIR" to a directory containing one of the above files. If
"Protobuf" provides a separate development package or SDK, be sure it has
been installed.
Thank you for your help!
Thanks to David's nudge and various CMake/C++ tutorials I was able to figure out a solution that works for my use case.
What I did:
I moved both libprotobuf.a as well as the respective include to a folder within my PROJECT_SOURCE_DIR
I cleaned up my eclectic mix of find_package, add_library, and find_protobuf
I added the linker flag -llog to bypass this issue
cmake_minimum_required(VERSION 3.5)
set (CMAKE_VERBOSE_MAKEFILE ON)
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_SHARED_LINKER_FLAGS "-llog")
list(APPEND CMAKE_PREFIX_PATH [
${CMAKE_PREFIX_PATH}
])
ADD_LIBRARY(protobuf STATIC IMPORTED)
SET_TARGET_PROPERTIES(protobuf PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/google/protobuf/${ANDROID_ABI}/libprotobuf.a)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/main/jniLibs/include/)
ADD_LIBRARY(cpp
SHARED
../cpp/rn-etsi-parser.cpp
cpp-adapter.cpp
)
TARGET_LINK_LIBRARIES(cpp PUBLIC protobuf)
# Specifies a path to native header files.
INCLUDE_DIRECTORIES(
../cpp
)
I'd be interested to know, however, if there is a way to 'inject' prebuilt protobuf libraries into CMake's find_protobuf workflow, so that I could make use of features like protobuf_generate_cpp.
My project is fairly simple. I have an app that includes a library written based on integration platfrom so it looks something like this:
My app
----> Extension
----> Main library
The app is cross-compiled to Android. All of them are based on CMake. I'm using CLion as an IDE. I've added a profile with custom toolchain required to build for Android (that is clang, clang++ for apropiate platform, cmake from Android SDK and make from Android NDK r20b). Problem is I have to call CMake 3 times (reload it in CLion) before it generates all of the files needed. Whole file is listed below.
On the first run it ignores the fact it is build for android (doesn't go into if (ANDROID) ) and copies the prebuilt sub-executable for linux (default)
On the second run it ignores the needed android.toolchain.cmake and when build on this stage it fails to add android headers to search path BUT chooses correct prebuilt sub-executable
On the the third run it uses the android.toolchain.cmake file AND chooses correct sub-executable.
After that I can hit build and everything compiles correctly.
The CMake I have:
add_executable(androidApp main.cpp)
target_include_directories(androidApp
PUBLIC
../submodules/exten/src/libraries/main_lib/lib/include
../submodules/exten/src/libraries/main_lib/sdk/rlogging/include) //Headers from main library
target_link_libraries(androidApp
PRIVATE
exten) //Extension
install(TARGETS androidApp DESTINATION ${CMAKE_SOURCE_DIR}/bin)
install(FILES ../submodules/exten/src/libraries/main_lib/integration_app/resources/someFile.zip DESTINATION ${CMAKE_SOURCE_DIR}/bin)
install(FILES ../resources/someFile2.zip DESTINATION ${CMAKE_SOURCE_DIR}/bin/resources)
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/bootsafe)
file(WRITE ${CMAKE_SOURCE_DIR}/bin/bootsafe/dummy "") //Required dir
add_custom_command(TARGET dongleApp POST_BUILD
COMMAND ${CMAKE_SOURCE_DIR}/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/arm-linux-androideabi/bin/strip --strip-debug dongleApp
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Stripping debug symbols")
if (ANDROID)
target_link_libraries(androidApp
PRIVATE
log)
endif (ANDROID) //Linking android lib
On different CMake (on the main library level) here's how the choosing on correct prebuilt is written
if(NOT ANDROID)
set(PREBUILD_NAME "linux")
else()
if(ANDROID_ABI STREQUAL "x86_64")
set(PREBUILD_NAME "android-x86")
else()
set(PREBUILD_NAME "android-arm")
endif()
endif()
The command that is used to generate makefiles:
/home/gravlok/companyName/app_v2/sdk/cmake/3.10.2.4988404/bin/cmake
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_MAKE_PROGRAM=/home/gravlok/companyName/app_v2/ndk/android-ndk-r20b/prebuilt/linux-x86_64/bin/make
-DCMAKE_C_COMPILER=/home/gravlok/companyName/app_v2/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi28-clang
-DCMAKE_CXX_COMPILER=/home/gravlok/companyName/app_v2/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi28-clang++
-DANDROID=ON
-DCMAKE_TOOLCHAIN_FILE=/home/gravlok/companyName/app_v2/ndk/android-ndk-r20b/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=android-28
-G "CodeBlocks - Unix Makefiles"
/home/gravlok/companyName/app_v2
Why do I need to run it 3 times in order to configure correctly?
I am trying to add a strip debug symbols step for my Android library which includes native shared libraries for different ABIs, e.g. x86/native-lib.so, x86_64/native-lib.so, arm64-v8a/native-lib.so, etc.
I understand that the strip command must be respective to each ABI. So, I need to invoke the correct strip command, for which I need to know its correct path during build time.
For example, for ABI x86_64, I need to have below path setting:
set(STRIP ~/Library/Android/android-ndk-r16b/toolchains/x86_64-4.9/prebuilt/darwin-x86_64/bin/x86_64-linux-android-strip)
add_custom_command(TARGET ${SHARED_LIBRARY_NAME} POST_BUILD
COMMAND ${STRIP}
"${DIST_LIBS_DIR}/${LIB_BUILD_TYPE}/${ANDROID_ABI}/lib${SHARED_LIBRARY_NAME}.so"
COMMENT "Strip debug symbols done on final binary.")
The path I need is illustrated like below:
So, my questions are:
Is there an existing CMake variable to point at this path, i.e. /android-ndk-r16b/toolchains/???/prebuilt/???/bin/???-???-???-strip?
If not, is there a way to form this path utilising other known Android CMake variable, e.g. ANDROID_NDK, ANDROID_ABI, etc?
Thanks #Alex Cohn a lot for pointing out the file android.toolchain.cmake which usually exists at directory ~/Library/Android/sdk/cmake/cmake_version_xxx/android.toolchain.cmake on macOS.
There are many useful Android CMake variables already configured inside, e.g.
ANDROID_NDK
ANDROID_TOOLCHAIN
ANDROID_ABI
ANDROID_PLATFORM
ANDROID_STL
ANDROID_PIE
ANDROID_CPP_FEATURES
ANDROID_ALLOW_UNDEFINED_SYMBOLS
ANDROID_ARM_MODE
ANDROID_ARM_NEON
ANDROID_DISABLE_NO_EXECUTE
ANDROID_DISABLE_RELRO
ANDROID_DISABLE_FORMAT_STRING_CHECKS
ANDROID_CCACHE
And the one ANDROID_TOOLCHAIN_PREFIX is exactly what I looked for, so my final CMake script comes into below:
add_custom_command(TARGET ${SHARED_LIBRARY_NAME} POST_BUILD
COMMAND "${ANDROID_TOOLCHAIN_PREFIX}strip" -g -S -d --strip-debug --verbose
"${DIST_LIBS_DIR}/${LIB_BUILD_TYPE}/${ANDROID_ABI}/lib${SHARED_LIBRARY_NAME}.so"
COMMENT "Strip debug symbols done on final binary.")
And I don't need to explicitly pass any additional arguments, i.e. DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake, from command line to the build process. Because, this file, i.e. android.toolchain.cmake, was already taken into account automatically by Android native build system.
You can use ${CMAKE_STRIP}. It is set appropriately when you use -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake. I hope it is OK also if you work with 'built-in' Android support with supported NDK version.
I'm pretty new to Android with NDK / CMake. However, I'm trying to embed a native CMake library into an Android Application. However, this library depends on OpenSSL.
That's why I downloaded a precompiled version of OpenSSL for Android.
However, when I try to sync the project I get the following error:
Could NOT find OpenSSL, try to set the path to OpenSSL root folder
in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_LIBRARIES)
(found version "1.1.0f")
Here is my (minimal) project structure
<app-name>
-app
- src
- main
- cpp
- library
- CMakeLists.txt
CMakeLists.txt
- distribution
- openssl
- armeabi
- include
- openssl
...
- lib
libcrypto.a, libssl.a
In my build.gradle I've defined the following:
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
}
}
The /app/src/main/cpp/CmakeLists.txt looks as follows:
cmake_minimum_required(VERSION 3.4.1)
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../distribution)
set(OPENSSL_ROOT_DIR ${distribution_DIR}/openssl/${ANDROID_ABI})
set(OPENSSL_LIBRARIES "${OPENSSL_ROOT_DIR}/lib")
set(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/include)
message("OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES}")
message("OPENSSL_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR}")
find_package(OpenSSL REQUIRED)
add_subdirectory(library)
find_package(...) searches for libraries in a few standard locations (read here - search for "Search paths specified in cmake"). In your case, it fails because it can't find OpenSSL on the machine you're trying to cross-compile the code for Android.
I know I also had various attempts on linking OpenSSL with my native c++ Android code, and the only way I managed it make it work, was the following:
SET(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../distribution)
SET(OPENSSL_ROOT_DIR ${distribution_DIR}/openssl/${ANDROID_ABI})
SET(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
SET(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/include)
SET(OPENSSL_LIBRARIES "ssl" "crypto")
#<----Other cmake code/defines here--->
LINK_DIRECTORIES(${OPENSSL_LIBRARIES_DIR})
ADD_LIBRARY(library #your other params here#)
TARGET_INCLUDE_DIRECTORIES(library PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(library ${OPENSSL_LIBRARIES})
I know I also tried to make find_package work correctly, by playing with some of it configuration properties, such as CMAKE_FIND_ROOT_PATH, and some other approaches, but I couldn't get it done.
Don't know if the solution I provided is the best approach, cmake-wise. Maybe someone has a better way of doing it, but alas, it solved my problem at the time.
Hope this helps
The reason OpenSSL is not found is because all the find_*() commands also rely on the variable CMAKE_SYSROOT variable, which is used to prefix paths searched by those commands. This is used when cross-compiling to point to the root directory of the target environment.
A solution is to add the path where OpenSSL is located to CMAKE_FIND_ROOT_PATH; the documentation of find_library() states:
The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more
directories to be prepended to all other search directories. This
effectively “re-roots” the entire search under given locations.
This solution works for me:
set(OPENSSL_ROOT_DIR "/path/to/openssl/for/android")
list(APPEND CMAKE_FIND_ROOT_PATH "${OPENSSL_ROOT_DIR}")
find_package(OpenSSL)
For me it worked to import openssl via gradle and then linking the fetched lib like described here
Either append NO_CMAKE_FIND_ROOT_PATH to your find_* command, e.g.
find_package(OpenSSL REQUIRED NO_CMAKE_FIND_ROOT_PATH)
Or set CMAKE_FIND_ROOT_PATH_MODE_* variables (like this) to NEVER. The following options fixed the Android and iOS builds on macOS for me:
-DOPENSSL_USE_STATIC_LIBS=TRUE \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=NEVER \
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=NEVER
I included a Boost-Header file to my test project using CMakeLists.txt. My some.cpp can include this header without any error, but i'm not able to run since the header file relies obviously on other Boost headers and its not finding the required files. The location of my files is in cpp folder and the boost files are in (C:\boost) a subdirectory:
..\src\main\cpp\boost\RequiredHeader.hpp.
For the include files in the "RequiredHeader" the compiler is looking at:
..\src\main\cpp\boost\boost\AnotherHeader.hpp.
CMakeLists.txt (Boost-part)
# ADD BOOST
message("Import Boost...\n")
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
set(Boost_INCLUDE_DIRS C:/boost_1_64_0/boost)
find_package(Boost 1.64.0)
if(Boost_FOUND)
message("Boost found! Link libraries...\n")
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(myDependantLib ${Boost_LIBRARIES})
endif()
Your help is highly appreciated!
Updated question:
How to tell CMake where my Boost header files are, since it still is not finding the right location, with BOOST_ROOT set?
Updated CMakeLists.txt
# ADD BOOST
message("Add boost...\n")
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
set(BOOST_ROOT C:/boost_1_64_0)
set(BOOST_INCLUDE_DIR C:/boost_1_64_0/boost)
FIND_PACKAGE(Boost 1.64.0 COMPONENTS foreach REQUIRED)
if(Boost_FOUND)
message("Boost found! Link libraries...\n")
target_link_libraries(calculator LINK_PUBLIC ${Boost_LIBRARIES})
endif()
This post here helped me in resolving this.
Include Boost-Header files and libs:
set(BOOST_ROOT C:/boost)
The path containing the include headers "boost/*.hpp" and libraries "stage/lib" or any other path where your compiled files have been output.
Then you need to specify the include header and libs paths. In the default case the headers are stored in the same directory as the root (since "boost" folder is searched automatically) and the libs as described in "stage/lib". Otherwise it should be "include" and "lib" of your output directory, while the boost version has to be corresponding to the one specified in version.hpp in the "boost" folder:
set( Boost_INCLUDE_DIR ${BOOST_ROOT}/include )
set( Boost_LIBRARY_DIR ${BOOST_ROOT}/lib )
set( Boost_Version 1_64 )
find_package( Boost ${Boost_Version} COMPONENTS system thread )
if( Boost_FOUND )
target_include_directories( <your_lib> PUBLIC/PRIVATE ${Boost_INCLUDE_DIR} )
# its possible to include boost to system path too:
# include_directories( SYSTEM ${Boost_INCLUDE_DIR} )
link_directories( ${Boost_LIBRARY_DIR} )
target_link_libraries( <your_lib> ${Boost_LIBRARIES} )
endif()
Then i was able to simply:
#include <boost/random.hpp>
#include <boost/whatever.hpp>
This worked for me on following environment:
Android Studio 2.3.1 and 3.0
NDK 14.1
Boost 1.56.0 and 1.64.0
Windows 10
If further explanation is needed, please comment your concerns!