0

To be frank I'm at my wit's end and I really need a place to crash. While compiling I am keeping getting a

error: linker command failed with exit code 1 (use -v to see invocation)

I presume it is due to incompability or simply different compiler versions between the project build and the boost libraries but as long as I read the binaries are perfect compatible(?).

Building Boost
I compiled via MinGW on Windows 10 but to exclude errors here I ended up building boost using this git shell script which worked with the latest versions of Boost (1.64.0) and NDK (r15b). I did it in the VirtualBox with Ubuntu 16.04 since I had not enough knowledge to adapt it to Windows 10 (at least I was not able to). Now I have shard and static libs compiled with gnu-4.9 and llvm-3.5 for x86 (which my emulator in AStudio is baded on too).

Android Studio
I am using Cmake to build the C/C++ libraries of my project. I have several C libs and one C++ lib that are dependant from each other. The last is the one using boost. Since all libraries are built and found with no error it seems to be a name mangling problem to me though all C header files have the preprocessor declaration: extern C. Except for the boost parts all is running flawlessly

CMake
The find_package() REQUIRED parameter is set and the Boost_DEBUG tells that all components have been found. Since at a certain point I got the error

undefined reference to boost::system::generic_category()

I added system to the components, so my minimalistic components setup contains only chrono and system like suggested on many other threads concerning this particular problem. I tried to link the boost libs individually, without success:

target_link_libraries( MyLib ${Boost_SYSTEM_LIBRARY} 
                                            ${Boost_CHRONO_LIBRARY}
                                            )

But now I have the problem described above and at this point I am hoisting the flag of truce. EVERY HINT is HIGHLY appreciated!! Thank you very much in advance!

CMakeLists.txt

set( Boost_DEBUG ON )
set( Boost_USE_STATIC_LIBS ON )
set( Boost_USE_STATIC_RUNTIME ON )
set( Boost_USE_MULTITHREADED OFF )
set( Boost_NO_SYSTEM_PATHS ON )
set( BOOST_ALL_DYN_LINK OFF )

set( BOOST_ROOT C:/MyBoost )
set( Boost_INCLUDE_DIR ${BOOST_ROOT}/include )
set( Boost_LIBRARY_DIR ${BOOST_ROOT}/lib )
set( Boost_Version 1.64.0 )

find_package( Boost ${Boost_Version} COMPONENTS system chrono )
if( Boost_FOUND )
    target_include_directories( MyLib PUBLIC/PRIVATE ${Boost_INCLUDE_DIR} )    
    link_directories( ${Boost_LIBRARY_DIR} )
endif()
target_link_libraries( MyLib ${Boost_LIBRARIES} )

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "My_ID"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions"
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

===== UPDATE =====

I added

externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions -DBOOST_SYSTEM_NO_DEPRECATED"
            }

to the build.gradle file and now it compiles as expected even including the thread or chrono libs!! Though some commands i decommented earlier are still not working now. I am getting following error now:

libboost_chrono.a: error adding symbols: File in wrong format

This should be a problem with the version of the apk and the boost libs??! How to ensure i am using the right Boost version if so?

kurtzmarc
  • 3,110
  • 1
  • 24
  • 40
int ermedi_8
  • 171
  • 1
  • 14
  • You can try to run "make VERBOSE=1" to see all the build commands, and check especially the linker command whether it really contains all the required libraries (`-lboost_system` in this case in particular). – EmDroid Jul 21 '17 at 11:51
  • Also, if the lib is actually linked but this error still present, you might try adding `-DBOOST_SYSTEM_NO_DEPRECATED` to the compiler flags (see here for details: https://stackoverflow.com/a/30877725/1274747) – EmDroid Jul 21 '17 at 11:57
  • @axalis I tried setting -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON but even after checking all output files (like cmakes and ninja's output files) i wasnt able to find the command you stated - where does the verbose output gets to? Your 2nd comment brought me further but i am still getting an error. Please check my updated question for details =) P.S. i checked that link but read only the accepted answer carefully and the other one only desultory - sorry for that – int ermedi_8 Jul 26 '17 at 16:35
  • Normally the verbose output goes to console, but I was only ever using make, not the ninja backend. The "file in wrong format" seems to imply some incompatibility between the code and the boost libs ... could be that they were build with different platform settings (different Android architecture target or alike) – EmDroid Jul 26 '17 at 17:47
  • Well, now i noticed a thing looking very strange to me: I am testing on a x86 emulator and previous to boost insertion I am able to test fine. but the error list contains following message too: "C:/Users/.../toolchains/mips64el-linux-android-4.9/...". But that is the wrong folder, and i do not compiled boost for the specified architecture, so is obvious the linker command fails??! How to tell gradle which toolchain to use? – int ermedi_8 Jul 27 '17 at 06:15
  • building boost for mips do not resolved the error either... is that only because android studio is building the apk for all architectures? – int ermedi_8 Jul 27 '17 at 07:01
  • Yes, you can add `abiFilters "x86"` next to **cppFlags**. – Alex Cohn Jul 27 '17 at 07:17
  • Thank you for your help so far! It worked like expected! Only weird thing remaining now: my app crashes whenever i use boost. I can call any function and include any header/lib it will not complain, it simply crashes at Java "System.loadLibrary()" if I try. Any of you has an idea why something like this would happen or should i open a new question about this? – int ermedi_8 Jul 28 '17 at 08:21
  • @axalis or AlexCohn if you summarize your both comments i will be able to accept it as an direct answer to my question! – int ermedi_8 Aug 03 '17 at 07:50
  • My actual error now is (from logcat): "dlopen failed: library "libboost_system.so" not found" even my cmake_build_output.txt states: "Found the following Boost libraries: system chrono ..." – int ermedi_8 Aug 03 '17 at 08:03

1 Answers1

1

To sumarize the comments:

The compilation error "undefined reference to boost::system::generic_category()" can be worked-around by adding the -DBOOST_SYSTEM_NO_DEPRECATED to the compiler flags (see here for further details: undefined reference to boost::system::system_category() when compiling).

To limit the build only to x86, you can provide the abiFilters "x86" in the "externalNativeBuild:cmake" section next to the cppFlags.

The dlopen() problem:

When the library is linked dynamically, it needs to be also in the shared library search paths, otherwise it might not be found when actually running the executable. So the Boost shared libs path needs to be put to the PATH (Windows) or LD_LIBRARY_PATH (Linux) (if it is not in the standard locations like '/lib[64]' or '/usr/local/lib[64]').

Alternatively you can build with static libraries instead:

set(Boost_USE_STATIC_LIBS   ON)
find_package(Boost REQUIRED ...)

Another alternative is to add the Boost libraries locations to the RPATH during the installation step:

set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

(but that might not be desirable for release builds, as it fixes the library location, which might be in a different place on the target machine)

EmDroid
  • 5,918
  • 18
  • 18
  • Thank you for this good answer and the many alternatives! Sadly by adding the libs path to the environmental PATH variable does not changed the error: it still crashed when loading the library. However using the static libraries results in "error: linker command failed with exit code 1". Any ideas about this and would you recommend using make instead of cmake? – int ermedi_8 Aug 03 '17 at 09:41
  • Did you try to restart the computer after adding to PATH? When running from Java, if the JVM is already started it might not pick up the new PATH setting until the reboot. Another option might be to provide the `java -Djava.library.path=/path/to/my/dll ` parameter. – EmDroid Aug 03 '17 at 12:09
  • With the static libs it is a bit strange ... when the linker fails, there should be at least some other information (like symbol resolution failures etc.) – EmDroid Aug 03 '17 at 12:11
  • Your hints helped me by finding out a thing i do not mentioned in the answer, since i do not thought it would make any difference - sorry for that. I moved the Boost include commands from the add_subdirectory() CMakeLists.txt file to the root CMakeLists.txt and Boost works like a charm. If it is the real cause of the problem, i could not investigate further at the moment, since i do not have time left but i will post an update as soon as i find out more. I very appreciated your help thank you so much! – int ermedi_8 Aug 09 '17 at 06:09
  • Well, that might be, because variables set in a sub-CMakeList are (by default) only propagated down the way, not up (or to siblings). So if you find_package in the root CMakeList.txt, every subdir CMakeList will have it, but not the other way around (you'd need to add the find_package(Boost) to every subdir CMakeLists where it is used - on the other side, that allows to use different set of Boost libraries in different subdirs). – EmDroid Aug 09 '17 at 09:14
  • Originally i had all Boost related commands only in the sub-CMakeList file, since i do not needed Boost anywhere except for that library. Later on i set Boost in the root and linked against it in the sub-CMakeList, still without success (without the find_package() there) - it continues to make sense? Is it the find_package or what could i have missed? I am not testing as i have no time to revert the changes as i said ::) – int ermedi_8 Aug 09 '17 at 11:29