Importing hxx file into a .mm file

Discussion in 'Mac Programming' started by estin, May 19, 2010.

  1. estin macrumors newbie

    Joined:
    May 19, 2010
    #1
    Hi all !.

    I'm doing a program that solve Bubble dynamics by a Boundary Integral Equation. I found the Seldon c++ algebra library that contains Matrix, Vector, and have iterative solvers , wich is very very useful to me in that specific program. I'm coding mostly on ObjC, with the classes that uses this library being ObjC++ (.mm files).

    The files that i'm having problems with are MeshNode.h /.mm and Solver.h/.mm . I'm getting a Duplicate symbols error if I both include the principal Seldon header file "Seldon.hxx" in MeshNode.mm and Solver.mm.

    I can't figure out what's happening, because I need to include that header file in these two classes's implementation files to use the library. If I remove the #import "Seldon.hxx" file in one of the two files, it compiles fine, however in that file I'm not capable to use Seldon classes.

    The error is :
    ld: duplicate symbol Seldon::ColMajor::GetFirst(int, int)in /Users/estin/Documents/TFC/xcode/TFC/build/TFC.build/Debug/TFC.build/Objects-normal/x86_64/Solver.o and /Users/estin/Documents/TFC/xcode/TFC/build/TFC.build/Debug/TFC.build/Objects-normal/x86_64/MeshNode.o


    Here's my code:
    Code:
    
    //  Solver.h
    
    
    #import <Cocoa/Cocoa.h>
    #import "RungeStepper.h"
    #import "Entity.h"
    #import "MeshNode.h"
    
    @interface Solver : NSObject 
    {
    	NSMutableArray *entities;
    	// añadir parametros físicos
    }
    -(void) setParameters;
    
    -(void) resetParameters;
    
    -(void) setEntity:(Entity*) mesh;
    
    -(void) takeStep;
    
    -(double) calculateVolumeInEntity:(NSMutableArray*) entity;
    
    -(double) calculatePrincipalCurvatureInNode:(MeshNode*) theNode;
    
    -(void) solve;
    
    //integrations
    
    - (double) getPotentialInfluenceOnNode:(MeshNode*) nodei bySurfacesInNode:(MeshNode*) nodej;
    
    - (double) getVelocityInfluenceOnNode:(MeshNode*) nodei bySurfacesInNode:(MeshNode*) nodej;
    
    Code:
    //  Solver.mm
    
    #define SELDON_DEBUG_LEVEL_3
    #define SELDON_DEFAULT_ALLOCATOR NewAlloc
    #import "Solver.h"
    #import "Seldon.hxx"
    
    -(void) takeStep
    {
    	// this is the method where i'm going to use Seldon's classes
    }
    Code:
    //
    //  MeshNode.h
    
    
    #import <Cocoa/Cocoa.h>
    
    struct Location;
    
    @interface MeshNode : NSObject 
    {
    	double potential;
    	double source;
    	struct Location *location;
    	NSMutableArray *triangles; //triangles that contains this node
    }
    
    @end
    Code:
    //
    //  MeshNode.mm
    
    
    #import "MeshNode.h"
    #import "Seldon.hxx"
    
    using namespace Seldon;
    
    struct Location {
    	Vector<double> vertex;
    };
    
    @implementation MeshNode
    -(id) init
    {
    	if(self = [super init] ) 
    	{
    		location = new Location;
    	}
    }
    @end
    Any ideas? thanks in advance !.
     
  2. NickK1066 macrumors regular

    Joined:
    Jul 23, 2007
    #2
    Objective-C doesn't support namespaces which is the reason why you have two identical symbols in different files.
     
  3. estin thread starter macrumors newbie

    Joined:
    May 19, 2010
    #3
    Thanks for the reply

    Thanks NickK1066 for your quick answer.

    I have substituted it to:

    Code:
    #import "MeshNode.h"
    #import "Seldon.hxx"
    
    
    
    struct Location {
    	Seldon::Vector<double> vertex;
    };
    
    @implementation MeshNode
    -(id) init
    {
    	if(self = [super init] ) 
    	{
    		location = new Location;
    	}
    }
    @end
    however, I'm still getting the same error. it still gave me the same error if delete all the code referencing the Seldon library.

    I've noticed that Seldon.hxx is not a header only file but contains implementation. However in the documentation, they say that this is the file that I must include.
     
  4. NickK1066 macrumors regular

    Joined:
    Jul 23, 2007
    #4
    Yes, this is the reason they used namespaces (which can be abused to clean up sloppy programming). They have placed code that results in symbols being created. The compiler can't then use the namespace to add to the symbols and therefore you get duplicates.

    It's not as simple as making one instance of the symbols through conditional compilation (#ifndef etc) as it's likely that your two files will need their own instances of the object/data referenced by those symbols. It looks like the way the library would work with multiple callers is by using the namespace'd variables..

    You may need to encapsulate the library in a singleton that marshals your classes' access.
     
  5. estin thread starter macrumors newbie

    Joined:
    May 19, 2010
    #5
    Encapsulating the library

    Hey ! thanks again for your reply... I really appreiate your comments.

    By Encapsulating the library in a singleton (I went into google right now to figure out what are you telling me) you refer to get a class that manages the namespace? something like:

    Code:
    struct Seldon;
    @interface mysingleton : NSObject
    {
        struct Seldon *seldon;
    }
    +(id)newVector:(int) dimension;
    +(id)newBiCgStabSolver;
    +(double)dotProductVector:(id)vector1 by:(id)vector2;
    ...etc...
    @end
    and implements these kind of methods for this class? hope I'm wrong... but I can't figure out how to access the classes in the library in the different classes in my project without having information about in the implementation files. thanks again!.
     
  6. NickK1066 macrumors regular

    Joined:
    Jul 23, 2007
    #6
    It's so that there's a single 'implementation' of the sheldon library which is like making a single namespace for all your classes to use. If you need to hold context for each of your applications you could do that with a object for each application however the singleton becomes a liability with multi-threading in terms of performance..


    If you have performance issues you may want to look at this again - Objective-C OO uses message passing etc which prevents the compiler doing some optimisations such as inline and shared code segments etc.

    Just out of interest - the CgStab, is that doing 2/3D vector maths using a library which is using SSE optimisations?

    The reason I ask this is that in 2006 I looked at the use of ATI GPUs and GPGPU as a front end for GCC so I'm very familiar with the GCC compiler internals and the optimisations it performs.. along with parallel number crunching.

    If you have performance issues you have other options available on OSX:
    * Blocks with Grand Central - create chuncks of 2/3D processing as blocks and then allow the OS to shedule their processing over multiple CPUs.
    * OpenCL (GPGPU) where you use the GPU to process 1/2D arrays with their own mini programs which offer high returns for maths based issues.


    By encapsulating and 'abstracting away' the implementation of the library you can change the library to the above technologies later if there is a performance issue.

    In short all this was caused by having an unclean interface API in the original libraries.
     
  7. estin thread starter macrumors newbie

    Joined:
    May 19, 2010
    #7
    Thanks for the very useful info !. For the project I'm doing, it is basically to solve a Matrix system like Ax = b to get the potencial and velocity of the nodes in the mesh, and then timestep the positions of the nodes. That BiCgStab handles the system of equations wich is the most intensive part. The Seldon library is built using cBlas, and I have succesfully linked against the apple's Accelerate framework wich is supposed to have an implementation of the Blas with sse optimization(as apple claims the entire framework uses intensively sse or altivec features).

    Multithreading is another issue. Seldon doesn't handle multiple cpus. I have taken a look to OpenCl, and I found it very very interesting. Grand Central is another great option. See what I can do with that Seldon library, but thanks again.
     
  8. NickK1066 macrumors regular

    Joined:
    Jul 23, 2007
    #8
    Looks like the network issues at work didn't allow my edit to get through.

    The issue of performance you may find is that basic matrix operation such as dot product et al are usually implemented using inline code from C++ templates or C #define'd macros (yuck!) as OO has an overhead and high maths computing multiplies that overhead considerably.
    It may mean a different way of implementing is required using C++ classes performing all data operations and then having only a thin veneer of Objective-C to map the output into the OSX desktop. Just something to think about.

    If you program OpenCL you will end up redeveloping your data structures. There's no real way around it with GCC based compilers (ie Xcode). At the same time you'll need to look carefully at the inter-dependencies for operations which means looking at the algorithms from a parallel perspective not a serial paradigm.
    Lastly look carefully at the data transfers in and out of main memory with OpenCL. Everyone concentrates on IEEE compliance, MULA/sec etc but the PCI-E bus is a killer. Although you can get over 150GB/sec on-card, the PCI-E bus is still the bottleneck at a couple of GB/sec max. It just means you have to plan your data transfers and attempt to keep data on card between operations.
     
  9. ncl macrumors member

    Joined:
    Aug 16, 2008
    #9
    Objective-C++ does support namespaces. Plus, after a quick glance at the Seldon source, it appears there is only one namespace, "Seldon".
    This is perfectly normal since Seldon uses templates.

    To solve your original problem: you probably downloaded the tar.gz file, which doesn't declare getFirst as inline. You'll have to get the latest sources from the svn repository (I didn't tested them but the file Storage.cxx seems fixed).
     
  10. NickK1066 macrumors regular

    Joined:
    Jul 23, 2007
  11. estin thread starter macrumors newbie

    Joined:
    May 19, 2010
    #11
    Hey ! I'm learning a lot with both of you :)

    I downloaded the svn repository, and voila! these duplicated symbols are gone !. However this is not the end of the movie, as more duplicate symbols appears !. Declaring in the source these method inline solves the problem, however, there are such many duplicates ! It appear endless. So my newbie questions arrises:

    what I'm doing when I declare these methods inline? I know that inline substitutes the call by the block function.

    Is no symbol created when I declare a function inline?.

    Must I keep declaring that functions inline or is a crazy thing?.

    If I develop the entire solver in c++, plus a model interface to the controller in ObjC, will gcc be ok with including the library in multiple classes?.

    So many questions ... Thank a lot for your help!
     
  12. ncl macrumors member

    Joined:
    Aug 16, 2008
    #12
    Indeed. I just tried it and it appears that the seldon developers didn't test their library by including it in different modules.

    Not exactly. You are telling the compiler that it is preferred that the function call be substituted with the function body. However, the final decision is up to the compiler, and the compiler doesn't have to follow your advice.
    A symbol must be created. At the very least because the programmer may want to take the address of an inline function.
    Inline functions follow more or less the same rules as any other functions: if it is declared static (or, in C++, in an anonymous namespace), it will be visible only in the current module. If it is declared as extern (which inline functions are by default in C++), then it will be visible everywhere.
    Now, the difference is that when 2 modules contains the definition of the same function (for instance, because the definition is in a header file included by both modules, like in this case), the linker complains with a "duplicate symbol". However, with inline functions, no error is reported and you are assured that the function will have the same address in all modules (basically, only one copy is kept).
    (For reference, everything is explained in the C++ 2003 iso standard, section 7.1.2)

    Clearly, the seldon developers didn't think of the fact that the library may be included in multiple implementation files.
    So either you go on and declare everything inline (but that means making probably tedious changes to the library that you will have to redo if/when you use another version). Or, if it is possible, you find a way to include seldon in only one implementation file: you put your entire solver in one cpp/mm file and declare an interface, usable from the obj-c code, that doesn't use the seldon types.
     
  13. estin thread starter macrumors newbie

    Joined:
    May 19, 2010
    #13
    Thanks for all the great answers!.

    I tried to put inline every method or function that appeared as a duplicated symbol in xcode, but the last error it gave me was:

    ld: duplicate symbol Seldon::SeldonTrans in /Users/estin/Documents/TFC/xcode/TFC/build/TFC.build/Debug/TFC.build/Objects-normal/x86_64/Solver.o and /Users/estin/Documents/TFC/xcode/TFC/build/TFC.build/Debug/TFC.build/Objects-normal/x86_64/MeshNode.o

    wich seems to be a duplicated namespace? I have no idea.

    Better I will try to put all the solver in a monsterclass, as you said. I think tricking the library for my purposes can result (by my fault) in a total mess.
     
  14. NickK1066 macrumors regular

    Joined:
    Jul 23, 2007
    #14
    Maybe worth getting in contact with the Sheldon developers and ask when/if they'll fix their design issues/sloppy programming.

    The problem is that the header file is likely to have data definitions - that causes any file that includes/imports (regardless of inline) to have data elements as part of the object file. Both files then have the same duplicate data symbols.
     
  15. ncl macrumors member

    Joined:
    Aug 16, 2008
    #15
    Nope. SeldonTrans is a variable of type class_SeldonTrans declared in the header Seldon.hxx, line 129. So, as NickK1066 wrote, you have a duplicate data symbol. And fixing that is a little harder than simply adding "inline".
    It is probably the easiest way. Or you could try NickK1066's suggestion and contact the authors (they have a link for that on their homepage). They may be willing to fix their code.
     
  16. estin thread starter macrumors newbie

    Joined:
    May 19, 2010
    #16
    Ok, I already sent a mail to the developers this morning, explaining the problem and giving them a link to this thread. I'll keep this thread active as there is no much info about this library in other sites than the developer's website, and I'm sure that it saves a lot coding time for a lot of people who needs advanced algebra in c++!.

    Thank you guys!.
     

Share This Page