Linking to shared libraries in linux

Added by Ben Hymers over 1 year ago

Last stupid question for a while, I promise; I've nearly got this monster script running :)

C.LinkPrebuiltLibraries seems to work in an odd way under linux - it looks like it's taking the input list, adding '.a' to the end of each element, and adding them all to the end of the call to g++. I don't know if that syntax is supposed to be supported, but everything I can find online about specifying libraries to g++ says that each library should be given by "-l_library_", and g++ will handle prepending 'lib', appending '.a' and searching for the file. Is this not the way it should be done in JamPlus? The problems with doing it the way it does are that '.so' files don't get linked (and there's no simple way to do this), and that it doesn't search the library paths given by '-L' (specified in C.LinkDirectories), requiring the full path to be given. Also the documentation I read suggests that objects using a library should come later in the command than the request to link the library, but JamPlus is putting all the libraries at the end. Because of the other problems I've not gotten far enough to see if this is a problem or not though!

I've had a bit of a poke about in the c modules with the intention of changing this behaviour but it's all a bit beyond me I'm afraid. From the looks of it there needs to be a "C.FLibraries" rule to go alongside "C.FLibraryPaths" and co, but the library names are treated quite differently to the link directories elsewhere (presumably for tracking dependencies and whatnot) so I got a bit lost :(


Replies (8)

RE: Linking to shared libraries in linux - Added by Joshua Jensen over 1 year ago

Hi. I haven't forgotten about you. I've been only near a computer rarely the past week, so I'll get you an answer soon.

The short of it all is there are two ways of prebuilt libraries existing on disk on Linux/Mac OS X... one with liblibrary.a and one as just library.a (ignoring shared libraries). I'm not certain why there are two ways, but it causes me stress. Let's talk about the right way, though.

Josh

RE: Linking to shared libraries in linux - Added by Ben Hymers over 1 year ago

Hi Josh, no worries, I can't expect you to wait on me hand and foot :) You're still better at supporting your project than 99% of other project owners!

Using "-lthing" seems to be the preferred way since it automagically looks for .a and .so files (and .la files? I don't know a lot about building on Linux!). So I agree, it's probably the way worth thinking about.

For now I've been using this:

LIBRARIES = thing otherthing ;
C.LinkPrebuiltLibraries target : $(LIBRARIES) : : win32 ;
C.LinkFlags target : -l$(LIBRARIES) : : linux32 ;

Which works exactly as I would want this to work (excluding other platforms of course):

LIBRARIES = thing otherthing ;
C.LinkPrebuiltLibraries target : $(LIBRARIES) ;

It's not a bad workaround but of course it would be more intuitive for the latter to work like the former, to avoid confusing new users. I had another look at the C modules but I didn't get much further than last time, sorry!

RE: Linking to shared libraries in linux - Added by Ben Hymers over 1 year ago

Ok, so that wasn't entirely accurate; things specified with LinkFlags come before things specified with LinkPrebuiltLibraries on the command line, and libraries need to come after the object files that need them. Also of course the two methods differ in that one requires you to type 'path/to/lib/libXXX.a' for the library name whereas the other requires just 'XXX'.

The first of those points is much more important of course since it results in things just not working. The only way round it is to fix the jambase.

I've had another bit of a poke and I've managed to get it to work, but I've no idea if I've broken the dependency stuff in the process. Instead of being wordy I'll just give you the diffs. This first one is basically replicated in all the other gcc-based compiler .jam files too:

--- a/bin/modules/c-compilers/c-gcc.jam
+++ b/bin/modules/c-compilers/c-gcc.jam
@ -55,7 +55,7 @ actions updated together piecemeal C.Archive

actions C.Link
{
- "$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) $(>:C) $(NEEDLIBS:T) $(LINKLIBS)
+ "$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) $(>:C) $(NEEDLIBS:T) -l$(LINKLIBS)
}

--- a/bin/modules/c.jam
++ b/bin/modules/c.jam
@ -1013,11 +1013,7 @ rule C.LinkPrebuiltLibraries TARGET : LIBRARIES : THE_CON
local newLibraries ;
local lib ;
for lib in $(LIBRARIES) {
- if $(lib:S) {
- newLibraries += $(lib) ;
- } else {
- newLibraries += $(lib)$(SUFLIB) ;
- }
newLibraries += $(lib) ;
}
LINKLIBS.$(THE_PLATFORM:E=*).$(THE_CONFIG:E=*) on $(TARGET) += $(newLibr
}

As I say, it works for me, but I've not done enough testing to know whether this will work when those library dependencies get updated and so on. It looks like the rest of the code is naïvely using libXXX.a as the thing to depend on, when it could be libXXX.so or whatever, and now of course could be in any of the directories specified by LinkDirectories as it isn't a full path. So, I'll leave it up to you to decide whether this is a good fix or not!

RE: Linking to shared libraries in linux - Added by Ben Hymers over 1 year ago

No edit button. Nice. Here's what those diffs are supposed to look like. Sadly some of the lines have been chopped off still:

--- a/bin/modules/c-compilers/c-gcc.jam
+++ b/bin/modules/c-compilers/c-gcc.jam
@@ -55,7 +55,7 @@ actions updated together piecemeal C.Archive

 actions C.Link
 {
-       "$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) $(>:C) $(NEEDLIBS:T) $(LINKLIBS)
+       "$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) $(>:C) $(NEEDLIBS:T) -l$(LINKLIBS)
 }
--- a/bin/modules/c.jam
+++ b/bin/modules/c.jam
@@ -1013,11 +1013,7 @@ rule C.LinkPrebuiltLibraries TARGET : LIBRARIES : THE_CON
        local newLibraries ;
        local lib ;
        for lib in $(LIBRARIES) {
-               if $(lib:S) {
-                       newLibraries += $(lib) ;
-               } else {
-                       newLibraries += $(lib)$(SUFLIB) ;
-               }
+               newLibraries += $(lib) ;
        }
        LINKLIBS.$(THE_PLATFORM:E=*).$(THE_CONFIG:E=*) on $(TARGET) += $(newLibr
 }

RE: Linking to shared libraries in linux - Added by Joshua Jensen over 1 year ago

I've been testing something on Linux and Mac similar to your change. What it does is this:

C.LinkPrebuiltLibraries : stdc++ ;    # Adds -lstdc++ to the command line
C.LinkPrebuiltLibraries : /usr/lib/libstdc++.a   # Adds the full path to the command line without the -l

On Windows, the linking has been improved. It will resolve the location of the prebuilt library within JamPlus and add that location as a dependency to the TARGET. That way, when a prebuilt library changes, the application will relink.

I have not written code on Linux/Mac for this discovery yet.

Finally, sorry for the late response. I was out on vacation last week, and life has been busy. :(

-Josh

RE: Linking to shared libraries in linux - Added by Ben Hymers over 1 year ago

Sounds good! It'll be nice to have an 'officially supported' version of this to use, I've a feeling my approach is a bit short-sighted. Again, no worries about replying late, you're doing a great job keeping this project active. Cheers :)

RE: Linking to shared libraries in linux - Added by Joshua Jensen over 1 year ago

I have not published a build yet, but I have pushed all of the changes to the Git repository. Give it a whirl!

RE: Linking to shared libraries in linux - Added by Ben Hymers over 1 year ago

I spotted that, I'm one of your 8 watchers on github :) I should have some free time tonight to test it out, I'll let you know if there are any problems. Thanks!

(1-8/8)