how to create binary and .so using libtool
Asked Answered
C

4

12

I have a set of cpp files that I want to compile directly into a binary and also to compile into a shared library.

I have

bin_PROGRAMS=mybin
lib_LTLIBRARIES=libmylib.la

COMMON_SOURCES=f1.cpp f2.cpp f3.cpp

mybin_SOURCES=main.cpp $(COMMON_SOURCES)
libmylib_la_SOURCES=$(COMMON_SOURCES)

When I run this the cpp files are compiled twice, once with libtool and once without and sometimes libtool/automake complains

Makefile.am: object `f1.$(OBJEXT)' created both with libtool and without`

I tried putting COMMON_SOURCES into a .a file but then libtool complains when I link a .a with a .la (saying its not portable).

What I need is something like

bin_LTPROGRAMS=mybin

but that doesnt exist

edit: clarification - I am using automake/autoconf. What I have shown above is the meat of my automake Makefile.am

Connor answered 30/8, 2010 at 21:15 Comment(5)
I don't think you can make shared libraries with libtool. I believe you need to use the compiler. But you have forgotten some details. Looks like you are using some form of auto make etc. So you need to tell us the exact setup you are using (as it does not seem to be straight make).Sunbonnet
libtool is specifically for making shared libraries gnu.org/software/libtool/manual/libtool.htmlConnor
Why do you want to create libmylib.so, but instead of linking mybin to this shared object, statically link in the sources that comprise it?Baryon
i want to be able to distribute the binary as a free standing module. I want to be able to do the same with the .so. Honestly it makes senseConnor
herein the solution: gnu.org/software/automake/manual/html_node/…Patriciate
B
3

The issue is that the common sources need to be compiled differently when they are being made into a shared object than when they are being made into a static archive; in the case of the former, for example, g++ needs to be passed the -fPIC flag.

What I suggest is using two build directories.

Assuming this source hierarchy:

./src/Makefile.am
./src/f1.cpp
./src/f2.cpp
./src/f3.cpp
./src/main.cpp
./configure.ac
./Makefile.am

you would use something like this in ./src/Makefile.am:

bin_PROGRAMS = mybin
lib_LTLIBRARIES = libmylib.la

mybin_SOURCES = main.cpp
mybin_LDADD = libmylib.la

libmylib_la_SOURCES = f1.cpp f2.cpp f3.cpp

Then you create directories Release and ReleaseDisableShared in ./. In directory ./Release you run:

../configure && make

and in ./ReleaseDisableShared you run:

../configure --disable-shared && make

After building in each build directory, you use the mybin at ./ReleaseDisableShared/src/mybin and the libmylib.so at ./Release/src/libmylib.so.

See also:

Baryon answered 3/9, 2010 at 0:43 Comment(1)
this is what I ended up doing, roughly (I need both the binary and the lib so I build both in 2 different directories)Connor
I
6

Link against the library of common sources specifically:

bin_PROGRAMS = mybin
lib_LTLIBRARIES = libmylib.la

mybin_SOURCES = main.cpp
mybin_LDADD = libmylib.la
libmylib_la_SOURCES = f1.cpp f2.cpp f3.cpp

If libmylib.la ends up using files that shouldn't be linked into mybin, create a libtool convenience library, using a Makefile.am something like this:

bin_PROGRAMS = mybin
noinst_LTLIBRARIES = libcommon.la
lib_LTLIBRARIES = libmylib.la

mybin_SOURCES = main.cpp
mybin_LDADD = libcommon.la

libmylib_la_SOURCES = f4.cpp f5.cpp f6.cpp
libmylib_la_LIBADD = libcommon.la

libcommon_la_SOURCES = f1.cpp f2.cpp f3.cpp

This will link f1.cpp, f2.cpp, f3.cpp, f4.cpp, f5.cpp and f6.cpp into libmylib.la and main.cpp, f1.cpp, f2.cpp and f3.cpp into mybin.

Incarcerate answered 2/9, 2010 at 1:56 Comment(5)
i did this but I ended up with libmylib.la dynamically linked into mybin. I want it static. I put in mybin_LDFLAGS=-static but it still ended up dynamicConnor
If you want mybin to be statically linked, I think libtool will want you to put mybin_LDFLAGS = -all-static, not -static. See info (libtool)Link mode. Note that this will break --disable-static builds, unless you do something like AM_CONDITIONAL([HAVE_STATIC], [test "$enable_static" = yes]) and put the -all-static inside a conditional.Incarcerate
@pm100: When you say that you tried this, did you link directly with libmylib.la, or with a convenience library? It may be the case that a convenience library will link statically, and that will be the least problematic for you. Try using a convenience library.Incarcerate
i tried both and in both cases I ended up with the binary dynamically linking the libraries. I will try again with the convenience libConnor
If you absolutely must have static linkage (and I'm not sure why this is the case, given that you're installing the library anyway), and you can't get this method to work, try my other answer and let me know how that goes.Incarcerate
B
3

The issue is that the common sources need to be compiled differently when they are being made into a shared object than when they are being made into a static archive; in the case of the former, for example, g++ needs to be passed the -fPIC flag.

What I suggest is using two build directories.

Assuming this source hierarchy:

./src/Makefile.am
./src/f1.cpp
./src/f2.cpp
./src/f3.cpp
./src/main.cpp
./configure.ac
./Makefile.am

you would use something like this in ./src/Makefile.am:

bin_PROGRAMS = mybin
lib_LTLIBRARIES = libmylib.la

mybin_SOURCES = main.cpp
mybin_LDADD = libmylib.la

libmylib_la_SOURCES = f1.cpp f2.cpp f3.cpp

Then you create directories Release and ReleaseDisableShared in ./. In directory ./Release you run:

../configure && make

and in ./ReleaseDisableShared you run:

../configure --disable-shared && make

After building in each build directory, you use the mybin at ./ReleaseDisableShared/src/mybin and the libmylib.so at ./Release/src/libmylib.so.

See also:

Baryon answered 3/9, 2010 at 0:43 Comment(1)
this is what I ended up doing, roughly (I need both the binary and the lib so I build both in 2 different directories)Connor
I
2

If a target contains per-target CFLAGS (or similar), automake will make separate object files for building that target. Try adding some no-op flags to mybin, something like:

mybin_CPPFLAGS = -I.

or

mybin_CPPFLAGS = -DDUMMY -UDUMMY
Incarcerate answered 2/9, 2010 at 22:19 Comment(0)
Z
0

You have to give object files created with libtool a different extension so they do not conflict. In fact, those files are text files containing meta information for both object files with relocatable and non-relocatable code (this is controlled with -fPIC gcc command line argument). The real files created by libtool are usually stored in ".libs" subdirectory. The basic makefile will look like this:

CC = $(CXX)
LIBTOOL = libtool --quiet

SRC = lib.cpp test.cpp
LIB_SRC = lib.cpp $(SRC)
LIB_OBJ = $(LIB_SRC:.cpp=.lo)

EXE_SRC = exe.cpp $(SRC)
EXE_OBJ = $(EXE_SRC:.cpp=.o)

EXE = test
LIB = libmylib.la

all: $(EXE) $(LIB)

clean:
    $(RM) *.o *.lo $(EXE) $(LIB)

$(EXE): $(EXE_OBJ)

$(LIB): $(LIB_OBJ)
    $(LIBTOOL) --tag=CXX --mode=link $(LINK.cc) -shared -version-info 1:0 -rpath $(shell readlink -f .) -o $@ $< $(LDLIBS)

%.o: %.cpp
    $(COMPILE.cc) -o $@ $<

%.lo: %.cpp
    $(LIBTOOL) --mode=compile --tag=CXX $(COMPILE.cc) -o $@ $<
Ziwot answered 1/9, 2010 at 22:5 Comment(2)
Thx. But automake does exactly this. This is why I end up with the error message about having both .o and .lo. What I need is to only compile once to .lo and have the .lo files linked into both the binary and the lib. The only difference between the .o and .lo is that one has -fPIC and the other does not (and linkning -fPIC code into binary is harmless)Connor
You cannot link with .lo files, those are just text files and not an object code. In my example, though, it compiles twice. If you want to link against object with non-relocatable code (".o") files created by libtool, you can find them in your build directory, under ".libs" subdirectory.Ziwot

© 2022 - 2024 — McMap. All rights reserved.