Linking a Maya client library to libOpenMayalib.a fails, MLibrary::initialize can't be found (even though nm shows libOpenMayalib.a contains it) - linux

I'm trying to link my app with the Maya C++ API, but i get:
Debug/../src/main.cpp:80: undefined reference to `MLibrary::initialize(bool, char*, bool)'
but, nm shows:
nm libOpenMayalib.a | grep initialize
00000000000004b0 T _ZN8MLibrary10initializeEPcb
0000000000000380 T _ZN8MLibrary10initializeEbPcb
0000000000000000 b _ZZN8MLibrary10initializeEbPcbE13isInitialized
which seems to match MLibrary::initialize, that looks like:
class OPENMAYA_EXPORT MLibrary
{
public:
MLibrary ();
virtual ~MLibrary ();
static MStatus initialize (char* applicationName,
bool viewLicense = false);
static MStatus initialize (bool wantScriptOutput,
char* applicationName,
bool viewLicense = false);
static void cleanup( int exitStatus = 0 );
protected:
// No protected members
private:
// No private members
};
The linking process is run with:
g++ -L/usr/autodesk/maya2009-x64/lib -m64 -pthread -Wl,-rpath,/usr/autodesk/maya2009-x64/lib -lOpenMayalib -l3dGraphics -lAG -lAnimEngine -lAnimSlice -lAnimUISlice -lAppVersion -lAshliFX -lAshli -lAutoCam -lawCacheShared -lawnSolver -lawxml2 -lBase -lCgGL -lCg -lCloth -lCommandEngine -lcxaguard -lDataModel -lDebug -lDeformSlice -lDeformUISlice -lDependCommand -lDependEngine -lDevices -lDynSlice -lDynUISlice -lExplorerSlice -lExtensionLayer -lfbxfilesdk -lFoundation -lgcc_s -lGeometryEngine -lguide -lhairlib -lHalf -lHumanIKShared -lHWFoundation -lHWGL -lHWRenderMaya -lHWRender -lIex -liff -lIlmImf -lImage -lImageUI -lImath -lIMFbase -limf -lirc -lJasperSlice -lKinSlice -lKinUISlice -lManips -lMaya -lmocap -lModelSlice -lModelUISlice -lModifiers -lMotionCapture -lNurbsEngine -lNurbsSlice -lNurbs -lNurbsUISlice -lOpenMayaAnim -lOpenMayaFX -lOpenMayaRender -lOpenMaya -lOpenMayaUI -lPolyEngine -lPolySlice -lPoly -lPolyUISlice -lProjectSlice -lPsdTexture -lpython2.5 -lRenderModel -lRenderSlice -lRenderUISlice -lShared -lSharedUI -lstdc++ -lstdc++ -lSubdivEngine -lSubdivGeom -lSubdiv -lSubdivUI -lsvml -ltbbmalloc -ltbb -lTranslators -lUIComponents -lUrchinSlice -lUrchinUISlice -lXm -lzlib -o"BinaryGL3MdlMayaExporter" ./src/Exporter.o ./src/Format.o ./src/Generic.o ./src/Output.o ./src/main.o -lm -lgtk-x11-2.0 -ldl -lpthread -lgdk-x11-2.0
The system is Ubuntu Maverick 10.10, 64-bit, and Maya is 64-bit as well, and compiling with -m64 gives the same result.
I found a similar post http://area.autodesk.com/forum/autodesk-maya/sdk/link-errors-when-using-the-openmaya-api-on-linux/ i took some ideas from his file, like using the -Wl,-rpath, but, that doesn't change anything..
I also tried installing g++-4.1 as it seems to be the one mentioned in the scripts, but that didn't change anything either (current version is g++-4.4)
Thanks in regards
//Johan

The problem is the way you call MLibrary::initialize.
It expects a non-const char string, which is probably fed with a literal char string that is implicitly constant.
What you call is something like lib.initialize(false, "my app", false) which equals MLibrary::initialize(bool, const char*, bool) - this signature is indeed not exported by MLibrary.
What you have to do to make it work is to use a non-const application name, for example:
// char* appName = "my app"; would be deprecated as string literals are always const
char appName[] = {'m','y',' ','a','p','p'};
lib.initialize(false, appName, false);
Note: This is an interface bug as the application name should indeed be fed as a const char* - this bug is fixed in later maya versions.

Related

Dynamic Linker does not resolve symbol although the library is already loaded

I stumbled over the following problem in my large-grown project: I have a set of libraries which depend on each other and on external libraries. Of one dependency ("libvtkCommonCore-*.so"), there are different variants, which need to be used interchangeably. The variants have different suffixes ("libvtkCommonCore-custom1.so", "libvtkCommonCore-custom2.so" and so on). Thus I cannot link the library, which needs symbols from it, directly to the providing library. Rather I link the application of the library which uses it to the appropriate variant and then load my own library.
This approach generally works but fails under some circumstances and I'm a bit lost while finding out what goes wrong.
This situation is working:
Sketch of situation 1
("libA" needs symbols from "libvtkCommonCore". It is loaded at run time by the constructor of some static object in "libB" using a "dlopen" call with flags RTLD_LAZY|RTLD_GLOBAL. libvtkCommonCore* and libB were linked at build time to an executable)
This situation now ceases to work:
Sketch of situation 2
(actually the same as before but complicated by the fact that libvtkCommonCore* and libB are linked to another library libC at build time. This library is loaded from an executable at run time using "dlopen")
I investigated the case by setting LD_DEBUG to "files", "symbols" and/or "binding" and study the output. It reveals that libvtkCommonCore* is loaded, initialized and kept in memory all the time and before libA is loaded. When the linked tries to resolve "SymbolX" in libA, it does not search libvtkCommonCore, although it did for other libraries which needed the same symbol.
Note: I use Linux (Ubuntu 20) with the recent Gcc and CMake. Both the executable in situation 1 and "libC" in situation 2 were built with the flags "-Wl,--add-needed -Wl,--no-as-needed".
Note 2: if I launch the executable in situation 2 with LD_PRELOAD=libvtkCommonCore-custom1.so set, no errors appear.
I would be grateful for any hint how to continue debugging this issue.
A minimum example of the problem is comprised by these files:
libvtkCommonCore-custom1.cpp:
#include <iostream>
void SymbolX()
{
std::cout<<"This just does nothing useful."<<std::endl;
}
libA.cpp:
void SymbolX(); // in libvtkCommonCore-custom1.so
struct LibAStaticObject
{
LibAStaticObject()
{
SymbolX();
}
} libAStaticObject;
libB.cpp:
#include <dlfcn.h>
#include <iostream>
class LibALoader
{
public:
LibALoader()
{
void *handle = dlopen ( "libA.so", RTLD_LAZY|RTLD_GLOBAL|RTLD_NODELETE );
if ( !handle )
{
std::cerr<<"Could not load module library libA!\nReason: " << dlerror() << std::endl;
}
}
} libAloader;
libC.cpp
/*empty*/
executable_situation1.cpp:
#include <iostream>
int main(int argc, char*argv[])
{
std::cout<<"starting."<<std::endl;
return 0;
}
executable_situation2.cpp
#include <iostream>
#include <dlfcn.h>
class LibCLoader
{
public:
LibCLoader()
{
void *handle = dlopen ( "libC.so", RTLD_LAZY|RTLD_GLOBAL|RTLD_NODELETE );
if ( !handle )
{
std::cerr<<"Could not load module library libC.so!\nReason: " << dlerror() << std::endl;
}
}
} libCloader;
int main(int argc, char*argv[])
{
std::cout<<"starting."<<std::endl;
return 0;
}
CMakeLists.txt:
add_library(vtkCommonCore-custom1 SHARED libvtkCommonCore-custom1.cpp)
add_library(A SHARED libA.cpp)
add_library(B SHARED libB.cpp)
target_link_libraries(B dl)
add_library(C SHARED libC.cpp)
target_link_libraries(C vtkCommonCore-custom1 B)
set_target_properties(C PROPERTIES LINK_FLAGS "-Wl,--add-needed -Wl,--no-as-needed -Wl,--copy-dt-needed-entries")
add_executable(executable_situation1 executable_situation1.cpp)
target_link_libraries(executable_situation1 vtkCommonCore-custom1 B)
set_target_properties(executable_situation1 PROPERTIES LINK_FLAGS "-Wl,--add-needed -Wl,--no-as-needed -Wl,--copy-dt-needed-entries") #"-Wl,--no-as-needed")
add_executable(executable_situation2 executable_situation2.cpp)
target_link_libraries(executable_situation2 dl)
Run it by these commands:
$ mkdir build
$ cd build
$ cmake .. && make
$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./executable_situation1
This just does nothing useful.
starting.
$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./executable_situation2
./executable_situation2: symbol lookup error: ./libA.so: undefined symbol: _Z7SymbolXv
Indeed, the problem is that in situation 2 the libvtkCommonCore is not in the lookup scope of libA while in situation 1 it is in the global scope.
The only (probably ugly) solution I found was to put in a kind of a stub library that loads libvtkCommonCore along with libB using "dlopen" with option "RTLD_GLOBAL". This places libvtkCommonCore in the global lookup scope. The new library is then linked to libC instead of its direct dependencies.

Unable to load shared object with inherited class in a R package

I am creating a R package using Rcpp. In this package, I want to create classes that will not be exported to R, with a class inheriting from another.
I created a package with Rcpp.package.skeleton(), to which I added two files in the src directory.
I have a file A.h:
class A {
public:
virtual ~A();
};
class B : public A {
public:
B();
};
And a file A.cpp:
#include "A.h"
B::B() { }
When compiling the package, I get the following error:
Error in dyn.load(dllfile) :
unable to load shared object '.../test/src/test.so':
.../test/src/test.so: undefined symbol: _ZTI1A
I only find resources about exposing such classes to R, but I am wondering whether it would be possible to use such a class internally, without exposing it to R?
Edit: If I understand correctly, the files necessary for building the package are:
NAMESPACE:
useDynLib(test, .registration=TRUE)
exportPattern("^[[:alpha:]]+")
importFrom(Rcpp, evalCpp)
DESCRIPTION:
Package: test
Type: Package
Title: What the Package Does in One 'Title Case' Line
Version: 1.0
Date: 2020-06-23
Author: Your Name
Maintainer: Your Name <your#email.com>
Description: One paragraph description of what the package does as one
or more full sentences.
License: GPL (>= 2)
Imports: Rcpp (>= 1.0.4)
LinkingTo: Rcpp
RoxygenNote: 7.1.0
This has nothing to do with Rcpp. Your class A is simply "too virtual". If I combine your files A.h and A.cpp with a simple main.cpp of this form
#include <cstdio>
int main(int argc, char *argv[]) {
std::printf("Hello, world.");
}
and try to compile it I also get an error:
edd#rob:/tmp$ g++ -o A A.cpp main.cpp
/usr/bin/ld: /tmp/ccbuZv0r.o: in function `A::A()':
A.cpp:(.text._ZN1AC2Ev[_ZN1AC5Ev]+0xf): undefined reference to `vtable for A'
/usr/bin/ld: /tmp/ccbuZv0r.o: in function `B::~B()':
A.cpp:(.text._ZN1BD2Ev[_ZN1BD5Ev]+0x26): undefined reference to `A::~A()'
/usr/bin/ld: /tmp/ccbuZv0r.o:(.data.rel.ro._ZTI1B[_ZTI1B]+0x10): undefined reference to `typeinfo for A'
collect2: error: ld returned 1 exit status
edd#rob:/tmp$
Which is pretty much what you got from R as well
edd#rob:/tmp$ c++filt _ZTI1A
typeinfo for A
edd#rob:/tmp$
So your package was simply insufficient -- nothing to do with Rcpp.

How to compile rust code as PIC binary since rustc don't have '-fPIC' flag?

I tried to compile some rust code but rustc print out this error:
relocation R_X86_64_32S cannot be used against local symbol; recompile with -fPIC
But rustc don't have '-fPIC' flag so how can I compile PIC binary with rustc?
I tried '-C relocation-model=pic -C code-model=large' but still get this error.
EDIT:
I figured out the error! I use some assembly code in asm! macro and it use some address of outside symbol, that why rust try to use 'R_X86_64_32S' and since the binary is linked to 0xffff800000000000, it cause the error.
EDIT2:
This is the code that cause similar error:
#![feature(asm)]
fn main ()
{
unsafe
{
asm! ("lea rax, [label]
label:"
:
:
:
: "intel");
}
}
Error:
= note: /usr/bin/ld: main.main.7rcbfp3g-cgu.0.rcgu.o: relocation R_X86_64_32S against `.text._ZN4main4main17h9e0ea2b04575dfdbE' can not be used when making a PIE object; recompile with -fPIE
The errors can be fixed this way:
Fixed code:
#![feature(asm)]
fn main ()
{
unsafe
{
asm! ("call label
label:
pop rax"
:
:
:
: "intel");
}
}
The point is: you can't load a label address directly, but you must use a call to push that address into stack, then pop the address.

Unable to initialize static set of strings inside templatized class in CLang, works fine in GCC

I'm using Boost config_file_iterator to parse a parameters file for different modules in the standard Boost way:
[Module 1 name]
M1_Key1=value1
[Module 2 name]
M2_Key1=value2
For that, Boost has the nice feature to accept a std::set containing all the valid keys, to throw an exception in case a non-valid one is passed.
boost::program_options::detail::config_file_iterator cfgIt(configStream, ALLOWED_PARAMS);
In my code, I've a set of modules, each one with its own set of parameters, In each one of the module header I have (as non-member variables):
module1.h:
static const std::string MODULE1_NAME = "Module 1 name";
static const std::string MODULE1_KEY1 = "M1_Key1";
module2.h:
static const std::string MODULE2_NAME = "Module 2 name";
static const std::string MODULE2_KEY1 = "M2_Key1";
In the header file for the parameters parser:
class ParametersParser
{
static const std::set<std::string> ALLOWED_PARAMS;
}
Finally in the source file of that parameter parser groups all the allowed values for the config iterator from the different modules:
#include "module1.h"
#include "module2.h"
const std::set<std::string> ParametersParser::ALLOWED_PARAMS =
{{
MODULE1_NAME + std::string(".") + MODULE1_KEY1,
MODULE2_NAME + std::string(".") + MODULE2_KEY1
}};
since Boost expects that as the allowed parameters set, a set of string of the way "Module X Name.MX_KeyY", and that worked fine.
However, because of other reasons, I've templatized the class that parses the file, so now my set of strings is declared also in the same header file, as:
#include "module1.h"
#include "module2.h"
/* Class definition */
template <class T>
class ParametersParser
{
static const std::set<std::string> ALLOWED_PARAMS;
};
/* Static member initialization */
template <class T>
const std::set<std::string> ParametersParser<T>::ALLOWED_PARAMS =
{{
MODULE1_NAME + std::string(".") + MODULE1_KEY1,
MODULE2_NAME + std::string(".") + MODULE2_KEY1
}};
And here is where the problem arises: This compiles in both gcc 4.8.5 (CentOS 7.5 vanilla) and AppleClang 9.1.0.9020039 (MacOSX 10.3), but in MacOSX, the resulting set only contains a ".". It's like the static strings defined in the modules headers (MODULE1_NAME, MODULE1_KEY1, etc) are empty!!! In gcc/CentOS, it works fine. Unfortunately, I couldn't compile on gcc for MacOSX (It complains about unresolved dependencies with Boost), while CLang on CentOS (Apple LLVM version 9.1.0 (clang-902.0.39.2)) works fine too.
Do you have any clues what am I doing wrong? Is it something about using strings as static variables? I also tried declaring the set using the new initializer list syntax, const std::set<std::string> ParametersParser<T>::ALLOWED_PARAMS{{...}}, but didn't work either.
Thanks a lot for your help.

Microsoft optimizing compiler 8.00 linker issue

#include<stdio.h>
void CopyBuffer(char *dest, char *src, int len)
{
memcpy(dest, src, len);
}
int main()
{
char *text = "Hello";
char buf[20];
CopyBuffer(buf, text, 6);
}
While using MSVC to compile above code I am facing couple of linking error saying
unresolved external
One example is if I use memcpy it is throwing error message
error L2029: '_memcpy' : unresolved external error L2029:
'__acrtused' : unresolved external error L2029: '__aNchkstk' :
unresolved external
Do I need to add library path during linking. But I have also observed if I use maximum optimization using /Ox _memcpy and __aNchkstk don't appear. Linker version is as it appear in console
Microsoft (R) Segmented Executable Linker Version 5.60.339 Dec 5
1994

Resources