I built Tensorflow using the scripts provided in contrib/makefile of the TF repo. As far as I can tell from the terminal output the generated libtensorflow-core.a should have been compiled with -fPIC enabled.
Now when I try to link that library into the shared library of an Android NDK project with
add_library(lib_tf STATIC IMPORTED )
set_target_properties(lib_tf PROPERTIES IMPORTED_LOCATION ${TF_BUILD}/libtensorflow-core.a)
add_library(native-lib SHARED ${SRC})
target_link_libraries(native-lib lib_tf)
it complains with
libtensorflow-core.a(config.pb.o): requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC
This is the output of objdump
$ objdump -r libtensorflow-core.a
libtensorflow-core.a(test_log.pb.o): file format ELF32-arm-little
RELOCATION RECORDS FOR [.rel.text]:
0000075c R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite24WriteMessageMaybeToArrayEiRKNS0_11MessageLiteEPNS0_2io17CodedOutputStreamE
000009b8 R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite10WriteInt64EixPNS0_2io17CodedOutputStreamE
000009cc R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite10WriteInt64EixPNS0_2io17CodedOutputStreamE
00000a1c R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite16VerifyUtf8StringEPKciNS2_9OperationES4_
00000a34 R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite11WriteStringEiRKSsPNS0_2io17CodedOutputStreamE
00000a44 R_ARM_REL32 .LC3
...
So it seems it was compiled with -fPIC. I'm not sure what the problem is.
UPDATE:
I compiled it manually via the Android NDK arm toolchain and it worked. I don' know what Android Studio does differently.
my c++ toolchain gave me the same error today when I was trying
to link an object into a shared library for android. The error went away
when I fixed the namespace resolution I was using for an extern variable in the problem source file.
namespace {
namespace android {
extern int* sys_id ;
}
}
void home::fileList::report () {
// do stuff
initialize (android::sys_id) ;
// do stuff
}
above instigates "requires unsupported dynamic reloc" error, below succeeds
namespace m1 {
namespace android {
extern int* sys_id ;
}
}
void home::fileList::report () {
// do stuff
initialize (m1::android::sys_id) ;
// do stuff
}
Related
I want to Create a Static-Library from Ada-Code and deploy it to Developers without the GNAT-Toolchain (for C/C++ Code).
I will get following Linker-Errors when I try to Link Ada-Library ('.a') with a C-Program:
undefined reference to `__gnat_rcheck_CE_Overflow_Check'
undefined reference to `ada__text_io__put_line__2'
How can I achieve this ? It seams that I should link against the Runtime-library, but how ?
Test-Code:
main.c:
#include <stdio.h>
extern void adaTest();
extern int add5(int);
int main(){
adaTest();
int b = add5(2);
printf("--> %d \ndone.\n", b);
return 0;
}
ada_lib_project.gpr:
library project ada_lib_project is
for Languages use ("Ada");
for Library_Name use "My_Ada_Lib";
for Library_Dir use "my_generated_lib";
for Library_Kind use "Static";
end ada_lib_project;
adatestpacket.ads:
with Interfaces.C; use Interfaces.C;
package adatestpacket is
procedure adatest with
Export, Convention => C, External_Name => "adaTest";
function add5(x: in int) return int with
Export, Convention => C, External_Name => "add5";
end adatestpacket;
adatestpacket.adb:
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C; use Interfaces.C;
package body adatestpacket is
procedure adatest is
begin
Put_Line("This is executed ADA/SPARK-Code...");
null;
end adatest;
function add5(x: in int) return int is
begin
return x + 5;
end add5;
end adatestpacket;
Compiling:
gcc -c main.c -o main.o # .c -> .o
gprbuild -P ada_lib_project.gpr # .ad[sb] -> .a
gcc main.o -L my_generated_lib -l My_Ada_Lib -o a.out # Linking -- with undefined References
Probably the easiest way to do this is to simply also compile the C source with gprbuild (even if you can't do that in your target scenario, you can do it for testing and see with -v what GPRbuild does to get it to work):
with "ada_lib_project";
project My_Executable is
for Languages use ("C");
for Main use ("main.c");
end My_Executable;
You will also need to call adainit and adafinal to initialize / finalizate Ada packages:
#include <stdio.h>
extern void adainit();
extern void adafinal();
extern void adaTest();
extern int add5(int);
int main(){
adainit();
adaTest();
int b = add5(2);
printf("--> %d \ndone.\n", b);
adafinal();
return 0;
}
adainit and adafinal are generated by gnatbind for standalone libraries. I am not entirely sure whether GPRBuild takes care of this when seeing that you use an Ada library from a C executable; if not you'll need
package Binder is
for Default_Switches ("Ada") use ("-n");
end Binder;
in your library. After doing this, you should be able to do
gprbuild my_executable.gpr
If you want to do it without GPRbuild, the -n/adainit/adafinal part still applies and you need to link your executable with
-l<your-gnat-lib>
where <your-gnat-lib> is the Ada standard library of your GNAT version; last time I did this, it was something like gnat-2021. You may need to add a -L<directory-containing-that-lib> depending on where it's located.
(there may be mistakes in this answer since I cannot currently test it due to being on an M1)
Edit: If you really want to supply developers without any access to GNAT, you need to build an encapsulated, i.e. dynamic, library. This answer covers that process. If providing a static library is a requirement, you have to at least supply the GNAT standard library file.
For anyone whose interested in a Working-Implementation, these are the Changes from my Question:
main.c:
#include <stdio.h>
extern void adainit();
extern void adafinal();
extern void adaTest();
extern int add5(int);
int main(){
adainit();
adaTest();
int b = add5(2);
printf("--> %d \ndone.\n", b);
adafinal();
return 0;
}
ada_lib_project.gpr:
library project ada_lib_project is
for Languages use ("Ada");
for Library_Name use "My_Ada_Lib";
for Library_Dir use "my_generated_lib";
for Library_Kind use "static-pic";
for Library_Interface use ("adatestpacket");
package Binder is
-- "-Lada" set "ada" as Prefix for "init" and "final" Function
for Default_Switches ("Ada") use ("-n","-Lada");
end Binder;
end ada_lib_project;
Compiling:
gprbuild -P ada_lib_project.gpr # .adb -> .a
gcc main.c -L my_generated_lib -l My_Ada_Lib -l gnat_pic -ldl
For the last Command, I just need to Transfer the Library (My_Ada_Lib) and the Runtime (libgnat_pic.a) from GNAT/2021/lib/gcc/x86_64-pc-linux-gnu/10.3.1/rts-native/adalib to the remote Machine.
I have generated static binaries with -static. I don't know if something similar can work while generating your library or you will also need to have the GNAT runtime for linking with the C/C++ tools.
I'm working on a PHP 7 extension using Swig and am trying to link to libphp7.so. From my CMakeLists.txt file:
find_library(php7_lib php7 PATHS "/usr/local/Cellar/php/7.3.0/lib/httpd/modules" NO_DEFAULT_PATH)
target_link_libraries(navdb_php7_client_api ${php7_lib} dl)
But I get an error:
[100%] Linking CXX shared module .../lib/libnavdb_php7_client_api.so
...
ld: can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB) file '/usr/local/Cellar/php/7.3.0/lib/httpd/modules/libphp7.so' for architecture x86_64
The file I'm trying to link to:
$ file /usr/local/Cellar/php/7.3.0/lib/httpd/modules/libphp7.so
/usr/local/Cellar/php/7.3.0/lib/httpd/modules/libphp7.so: Mach-O 64-bit bundle x86_64
Any ideas on how to resolve this?
Although Apple recommends bundles be given the extension .bundle many developers give them the .so extension for the sake of cross-platform familiarity. On Linux, no distinction is made between a shared module (a bundle on MacOS) and a shared library (a dylib on MacOS.)
Understanding that, as ld states, you cannot link to an MH_BUNDLE on MacOS. It either needs to be a dylib to link it, or you need to load the .so using the dyld APIs.
This link gives an example of how to dynamically load a bundle on MacOS:
#include <stdio.h>
#import <mach-o/dyld.h>
int main( )
{
int the_answer;
int rc; // Success or failure result value
NSObjectFileImage img; // Represents the bundle's object file
NSModule handle; // Handle to the loaded bundle
NSSymbol sym; // Represents a symbol in the bundle
int (*get_answer) (void); // Function pointer for get_answer
/* Get an object file for the bundle. */
rc = NSCreateObjectFileImageFromFile("libanswer.bundle", &img);
if (rc != NSObjectFileImageSuccess) {
fprintf(stderr, "Could not load libanswer.bundle.\n");
exit(-1);
}
/* Get a handle for the bundle. */
handle = NSLinkModule(img, "libanswer.bundle", FALSE);
/* Look up the get_answer function. */
sym = NSLookupSymbolInModule(handle, "_get_answer");
if (sym == NULL)
{
fprintf(stderr, "Could not find symbol: _get_answer.\n");
exit(-2);
}
/* Get the address of the function. */
get_answer = NSAddressOfSymbol(sym);
/* Invoke the function and display the answer. */
the_answer = get_answer( );
printf("The answer is... %d\n", the_answer);
fprintf(stderr, "%d??!!\n", the_answer);
return 0;
}
I found out how/what to do from this link:
Clang and undefined symbols when building a library
The libphp7.so doesn't need to be linked to at compile time, run-time works fine. This can be enabled by setting a CXX_FLAG (see the link for details).
I thought one feature of dynamic libraries (and by extension Apple's Mach-O Frameworks) was to leave some symbols (methods) undefined until the using application gets linked, but it appears all symbols have to be resolved for clang++ to successfully build a Framework.
For example, in building a framework for flight simulations, one might leave a C routine named aero undefined (but with an 'extern aero()' specification.) But XCode 4.2 refuses to build the framework, calling _aero an "undefined symbol."
Here's the header file included by both Objective-C and ANSI-C routines:
// FlightVehicleCAdapter_data.h
#ifndef FlightVehicleCAdapter_data_h
#define FlightVehicleCAdapter_data_h
#ifdef __cplusplus
external "C" {
#endif
extern void aero( void );
#ifdef __cplusplus
}
#endif
And here is where it gets called:
// FlightVehicleCAdapter.m
-(void) calcAero {
aero();
[self setBodyAeroForce_lb: [lsVector3 vectorFromScalarX:fv_data->f_aero_v.x
Y:fv_data->f_aero_v.y
Z:fv_data->f_aero_v.z]];
[self setBodyAeroMoment_ftlb:[lsVector3 vectorFromScalarX:fv_data->m_aero_v.x
Y:fv_data->m_aero_v.y
Z:fv_data->m_aero_v.z]];
}
I had hoped to be able to define the real aero() routine in the application that would link this framework, but when trying to build the framework itself the linker refuses to build it without a concrete aero() implementation:
Undefined symbols for architecture [i386|x86_64]:
"_aero", referenced from:
-[FlightVehicleCAdapter calcAero] in FlightVehicleCAdapter.o
So I then defined a dummy aero() routine:
// dummy_aero.c
// not showing fv_data structure definition for clarity
void aero(void){
fv_data->f_aero_v.x = 0.0;
fv_data->f_aero_v.y = 0.0;
fv_data->f_aero_v.z = 0.0;
fv_data->m_aero_v.x = 0.0;
fv_data->m_aero_v.y = 0.0;
fv_data->m_aero_v.z = 0.0;
}
This definition of aero() satisfies clang++ such that the Mach-O framework (dynamic library) is successfully built. But when I link the resulting framework with the application target which includes a non-trivial aero() routine, the framework's dummy aero() is being called instead of the application's aero().
You need to pass the -bundle_loader <executable> option to the linker, although I'm not sure that works for frameworks. Alternatively, you can use -undefined dynamic_lookup.
You need to do this for aero():
#ifdef __cplusplus
extern "C" {
#endif
extern void aero( void );
#ifdef __cplusplus
}
#endif
This makes sure the function is declared in C++ to have a C-resolvable name. C++ builds names differently than C does.
Note that then aero() can be linked at runtime.
I have a .dll I suspect uses __stdcall functions, but totally undecorated names (not even an underscore or # sign). I wrote a .def file for it with aliases like
func1 = func1
func1#4 = func1
but I think lib (which I am using to create the import library from the .def file) is ignoring the aliases (the linker still says func1#4 is undefined)
How can I create an import library that will map func1#4 to func1?
I don't know if it possible to create right .lib file with lib.exe, so I suggest to create a DLL with stubs of functions exported by original DLL.
Example dll.cpp file:
void __stdcall foo(int) {}
dll.def file:
EXPORTS
foo=foo
Then you compile it, from IDE, or command line:
cl dll.cpp /link /dll /def:dll.def /noentry
It will create correct dll.lib file, so you can use it with code like this:
void __stdcall foo(int);
#pragma comment(lib, "dll")
int main()
{
foo(42);
}
You should be declaring the function prototype as extern "C" as you are (obviously) compiling with in C++ mode:
extern "C" void func1(void); // correct prototype, add __stdcall if necessary?
You can wrap entire sections of a header file inside
extern "C" {
// ... C compatible declarations
}
I am working on an application(contains 3 projects, 2 in c++ and one in Objective-C) which compiles perfectly for LLVM GCC compiler. But when I switch the compiler to 'Apple LLVM compiler 3.0' I found one strange error as follow:
error: implicit instantiation of undefined template 'EList<ETemplateString<char>>'
and above error shows in the following line of code:
EList<EString> outlist;
with the forward declared EList as follows:
template <class T> class EList; // forward decls
EString is declared as follow:
typedef ETemplateString<TCHAR> EString;
and rest of the used templates are defined as:
template <class T> class ETemplateString
{
//
//
//
}
and TCHAR is declared as:
typedef char TCHAR;
can anybody please let me know why it's compiling good with GCC and throwing errors in 'Apple LLVM compiler 3.0'
See http://clang.llvm.org/compatibility.html#undep_incomplete .