views:

74

answers:

4

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

A: 

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 $@ $<
Vlad Lazarenko
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)
pm100
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.
Vlad Lazarenko
+1  A: 

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.

Jack Kelly
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 dynamic
pm100
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.
Jack Kelly
@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.
Jack Kelly
i tried both and in both cases I ended up with the binary dynamically linking the libraries. I will try again with the convenience lib
pm100
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.
Jack Kelly
A: 

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
Jack Kelly
gross :P ......
Matt Joiner
+1  A: 

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:

Daniel Trebbien
this is what I ended up doing, roughly (I need both the binary and the lib so I build both in 2 different directories)
pm100