Trying to cross-compile an android app from linux using arm-linux-androideabi-g++, I get an error that the header file cstdarg can not be found.
common.h:27:19: fatal error: cstdarg: No such file or directory
compilation terminated.
If I look into the /usr/arm-linux-androideabi/include/, the header is not there but other c++ header files are present. How can I fix this problem ?
<cstdarg> is not a system header, in sense that it comes from C++ standard library. Looks like you've missed to add C++ headers to command line. They are placed under $ANDROID_NDK/sources/cxx-stl/. Of course ensure that you're using header for appropriate library implementation.
Also you may need to include complier-specific C-headers (at least <stdarg.h> as it is used by <cstdarg>).
Some of standard headers are compiler-specific because they use some compiler-specific extensions, intrinsics, so on. <stdarg.h> is one of them. Because of their nature there is no much sense to put them to generic sysroot include directory. Look under $ANDROID_NDK/toolchains/ directory.
Related
I am trying to build an executable for Android with cross compiling, everything works but the executable complains that it could not find the .so file it needs, which is in the same directory as the executable.
So what I did is to add the following lines
set(TARGET myapp)
# following 4 lines added to add RPATH of ./ to the binary
# so it searches the .so in the same directory
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_SKIP_RPATH FALSE)
set(CMAKE_INSTALL_RPATH $ORIGIN)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
# add source code to target
add_executable(${TARGET} src.cpp)
...
However, it builds the executable, but RPATH seems not working no matter how I play with the four lines above, I just could not find any RPATH info in the binary using readelf or objdump.
I also tried set_target_properties(${TARGET} PROPERTIES INSTALL_RPATH $ORIGIN) but still not working.
Did I miss use anything here for RPATH configuration?
update
just to note that if I build the app for host(Linux) (using the same cmake file except using the android ndk tool chain) then everything is fine, I see $ORIGIN in the binary RPATH using readelf.
although i dont know what is been done in android ndk tool chain
This is probably not what you want:
(I am mentioning it just to be complete with my answer)
I assume that $ORIGIN is an environment variable. If that is the case you need to explain to CMake that it is such an variable. You can use $ENV{VAR} to do this, e.g.:
set(CMAKE_INSTALL_RPATH $ENV{ORIGIN})
This is probably what you want:
Ofcourse if the variable is not accessible during CMake generation step. You can try to use bracket arguments, however I do not think that alone would work (see last note at the bottom). Bracket arguments [=[...]=] tell CMake to skip the evaluation, because $ is a special character. e.g.:
set(CMAKE_INSTALL_RPATH [=[$ORIGIN]=])
To understand what [=[]=] do here is a simple example:
set(FOO "bar")
message(STATUS ${FOO})
message(STATUS [=[${FOO}]=])
Should output
bar
${FOO} #<-- evaluation of ${FOO} was skipped
Also if I'm not mistaken you also need to pass $ORIGIN to linker with single quotes so that it doesn't get evaluated during linking, i.e.
'$ORIGIN'
#and not $ORIGIN
Looking around on the net I have seen a lot of code like this:
include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)
target_include_directories(app SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS})
target_link_libraries(app ${SDL2_LIBRARIES})
However that seems to be the wrong way about doing it, as it only uses the include directories and libraries, but ignored defines, library paths and other flags that might be returned by pkg-config.
What would be the correct way to do this and ensure that all compile and link flags returned by pkg-config are used by the compiled app? And is there a single command to accomplish this, i.e. something like target_use(app SDL2)?
ref:
include()
FindPkgConfig
First of, the call:
include(FindPkgConfig)
should be replaced with:
find_package(PkgConfig)
The find_package() call is more flexible and allows options such as REQUIRED, that do things automatically that one would have to do manually with include().
Secondly, manually calling pkg-config should be avoid when possible. CMake comes with a rich set of package definitions, found in Linux under /usr/share/cmake-3.0/Modules/Find*cmake. These provide more options and choice for the user than a raw call to pkg_search_module().
As for the mentioned hypothetical target_use() command, CMake already has that built-in in a way with PUBLIC|PRIVATE|INTERFACE. A call like target_include_directories(mytarget PUBLIC ...) will cause the include directories to be automatically used in every target that uses mytarget, e.g. target_link_libraries(myapp mytarget). However this mechanism seems to be only for libraries created within the CMakeLists.txt file and does not work for libraries acquired with pkg_search_module(). The call add_library(bar SHARED IMPORTED) might be used for that, but I haven't yet looked into that.
As for the main question, this here works in most cases:
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
...
target_link_libraries(testapp ${SDL2_LIBRARIES})
target_include_directories(testapp PUBLIC ${SDL2_INCLUDE_DIRS})
target_compile_options(testapp PUBLIC ${SDL2_CFLAGS_OTHER})
The SDL2_CFLAGS_OTHER contains defines and other flags necessary for a successful compile. The flags SDL2_LIBRARY_DIRS and SDL2_LDFLAGS_OTHER are however still ignored, no idea how often that would become a problem.
More documentation here http://www.cmake.org/cmake/help/latest/module/FindPkgConfig.html
If you're using cmake and pkg-config in a pretty normal way, this solution works.
If, however, you have a library that exists in some development directory (such as /home/me/hack/lib), then using other methods seen here fail to configure the linker paths. Libraries that are not found under the typical install locations would result in linker errors, like /usr/bin/ld: cannot find -lmy-hacking-library-1.0. This solution fixes the linker error for that case.
Another issue could be that the pkg-config files are not installed in the normal place, and the pkg-config paths for the project need to be added using the PKG_CONFIG_PATH environment variable while cmake is running (see other Stack Overflow questions regarding this). This solution also works well when you use the correct pkg-config path.
Using IMPORTED_TARGET is key to solving the issues above. This solution is an improvement on this earlier answer and boils down to this final version of a working CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
project(ya-project C)
# the `pkg_check_modules` function is created with this call
find_package(PkgConfig REQUIRED)
# these calls create special `PkgConfig::<MODULE>` variables
pkg_check_modules(MY_PKG REQUIRED IMPORTED_TARGET any-package)
pkg_check_modules(YOUR_PKG REQUIRED IMPORTED_TARGET ya-package)
add_executable(program-name file.c ya.c)
target_link_libraries(program-name PUBLIC
PkgConfig::MY_PKG
PkgConfig::YOUR_PKG)
Note that target_link_libraries does more than change the linker commands. It also propagates other PUBLIC properties of specified targets like compiler flags, compiler defines, include paths, etc., so, use the PUBLIC keyword with caution.
It's rare that one would only need to link with SDL2. The currently popular answer uses pkg_search_module() which checks for given modules and uses the first working one.
It is more likely that you want to link with SDL2 and SDL2_Mixer and SDL2_TTF, etc... pkg_check_modules() checks for all the given modules.
# sdl2 linking variables
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2 SDL2_ttf SDL2_mixer SDL2_image)
# your app
file(GLOB SRC "my_app/*.c")
add_executable(my_app ${SRC})
target_link_libraries(my_app ${SDL2_LIBRARIES})
target_include_directories(my_app PUBLIC ${SDL2_INCLUDE_DIRS})
target_compile_options(my_app PUBLIC ${SDL2_CFLAGS_OTHER})
Disclaimer: I would have simply commented on Grumbel's self answer if I had enough street creds with stackoverflow.
Most of the available answers fail to configure the headers for the pkg-config library. After meditating on the Documentation for FindPkgConfig I came up with a solution that provides those also:
include(FindPkgConfig)
if(NOT PKG_CONFIG_FOUND)
message(FATAL_ERROR "pkg-config not found!" )
endif()
pkg_check_modules(<some-lib> REQUIRED IMPORTED_TARGET <some-lib>)
target_link_libraries(<my-target> PkgConfig::<some-lib>)
(Substitute your target in place of <my-target> and whatever library in place of <some-lib>, accordingly.)
The IMPORTED_TARGET option seems to be key and makes everything then available under the PkgConfig:: namespace. This was all that was required and also all that should be required.
There is no such command as target_use. But I know several projects that have written such a command for their internal use. But every project want to pass additional flags or defines, thus it does not make sense to have it in general CMake. Another reason not to have it are C++ templated libraries like Eigen, there is no library but you only have a bunch of include files.
The described way is often correct. It might differ for some libraries, then you'll have to add _LDFLAGS or _CFLAGS. One more reason for not having target_use. If it does not work for you, ask a new question specific about SDL2 or whatever library you want use.
If you are looking to add definitions from the library as well, the add_definitions instruction is there for that. Documentation can be found here, along with more ways to add compiler flags.
The following code snippet uses this instruction to add GTKGL to the project:
pkg_check_modules(GTKGL REQUIRED gtkglext-1.0)
include_directories(${GTKGL_INCLUDE_DIRS})
link_directories(${GTKGL_LIBRARY_DIRS})
add_definitions(${GTKGL_CFLAGS_OTHER})
set(LIBS ${LIBS} ${GTKGL_LIBRARIES})
target_link_libraries([insert name of program] ${LIBS})
I'm trying to build libavformat with this MAKEFILE. Although the makefile includes avio.o file in its build instruction but it doesn't add any symbol for the functions that are declared on the header file url.h. Source folder which includes the avio.c, avio.h and url.h files can be found HERE.
The nm command for avio.o returns
nm: avio.o: File format not recognized
file command on avio.o shows the following output
avio.o: LLVM IR bitcode
I have checked the nm command on the generated libavformat.so and did not find any symbols for the functions declared on the url.h file
I have been stuck on this for two days. Could not figure out how to solve this problem!
Calling the ff_check_interrupt method and results in
undefined reference to 'ff_check_interrupt'
Configurations and flags.
FFmpeg Configuration File: Config.h
FFmpeg Root MakeFile: Root MakeFile
CC, CXX, CFLAGS, LDFLAGS: FLAGS
First off, a function declared by url.h should be defined in url.c, not in avio.c.
Second the only use of the ff_check_interrupt in avoi.c is within a static inline function, so indeed the toolchain is likely optimizing this symbol away.
I think what's occurring for you is that the toolchain making the decision that this is only used in this compilation unit.
Moving the definition of ff_check_interrupt to 'url.c' should resolve the issue. This is a library though, so out of your control.
However, this doesn't answer why thousands of users on Github have this same library in their code. I'd suggest comparing your Makefile against those (e.g. first search return is this one.
I notice this question:
Two header with same name in include path
But the problem I encounter is the include path is system include path.
Suppose two headers: dir1/header.h dir2/header.h, they are located in system include path, and dir1 is searched firstly, but the one I really want is dir2/header.h. What could I do in this case?
It's in the Android NDK environment.
Suppose the two system include paths are:
dir1:$(NDK_ROOT)\sources\cxx-stl\gabi++\include
dir2:$(NDK_ROOT)\toolchains\arm-linux-androideabi-4.6\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.6\include
Now I want the header in dir2. But the Android compiler will search the header in dir1 firstly. If I used the -I option, How can I change the dir2 path into a platform-independent path (e.g. windows-x86_64 may be linux-x86)?
You must use #include "dir2/header.h" in your source file, then on the compile line you list the parent directory with -I; so for example if the fully-qualified pathname of the second header was /usr/local/include/dir2/header.h you would add -I/usr/local/include to your compile line.
ETA
Nate that in makefiles you should always use forward slashes, not backslashes.
Also, the compiler always searches the directories you provide on the command line with -I, in the order you specify them, before it searches any of the standard locations. So I don't really understand the problem. If the default location is the one you don't want anyway, then just add a -I flag pointing to the other one and it'll be used instead.
I encountered the same problem. There are two header files 'cuda.h', one in the system path '/usr/local/cuda/include/cuda.h', anoter one is specified with '-I' in Makefile, i.e. -I
${PWD}/dependency/libtorch/include/torch/csrc/api/include/torch/cuda.h.
I want to include the first one, but the second one was referred. Then I tried to replace '#include <cuda.h>' with '#include "../../../local/cuda/include/cuda.h"'. It works.
Hope this could help you.
I have built FFmpeg for Android and want to use it in an application like so:
System.loadLibrary("avutil");
System.loadLibrary("swscale");
System.loadLibrary("avcodec");
System.loadLibrary("avformat");
The build output are lib*.so, lib*.so.MAJOR and lib*.so.MAJOR.MINOR.OTHER files. Inside the shared objects are references like lib*.so.MAJOR, for example libswscale.so.2 requires libavutil.so.52.
Now if I put the *.so files in the project's libs folder (more exactly libs/armeabi-v7a), I of course get
01-25 12:06:40.270: E/AndroidRuntime(2905): java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1936]: 107 could not load needed library 'libavutil.so.52' for 'libswscale.so' (load_library[1091]: Library 'libavutil.so.52' not found)
However if instead I put the *.so.MAJOR files in the libs folder to solve the linking exception, I get the same error when running the app from Eclipse. And I noticed the files do not even get exported if I create an APK! So how do I tell Eclipse to package the *.so.MAJOR files as libraries? Or alternatively, how do I compile the shared objects in a way that they reference each other by *.so instead of *.so.MAJOR?
EDIT: It seems there's no way to package *.so.XYZ files automatically.
Didn't find a solution to take the .so.MAJOR files as I wished. It seems to me that the Android build system only copies *.so files automatically and doesn't allow other file extensions.
So I rewrote the FFmpeg makefiles to have the shared objects reference each other by libXXX.so.
In library.mak, I replaced $(SHFLAGS) in the following recipe
$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SUBDIR)lib$(NAME).ver
$(SLIB_CREATE_DEF_CMD)
$$(LD) $(SHFLAGS) $(LDFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS)
$(SLIB_EXTRA_CMD)
so that the third line looks like
$(subst $$(#F),$(SLIBNAME),$(SHFLAGS))
For those who don't understand the substitution (like me before), check this directly related answer.
Actually, you don't need to do that.
What you need to do is edit the configure file.
And find out this:
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'
Modified them to be:
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'