There are a lot of issues mixed up together in your email, and the libtool docs don't help to clarify. The major issue is that linking a C++ shared library with 'ld' does not always produce something that will dlopen successfully into a process (Note that dlopen is used both at runtime and by ld.so at process startup time, so if it links and the process starts up, you can also be sure it'll dlopen at runtime successfully).
If you use a Makefile generated by configure then you can't get rid of libtool, I think it is used whenever you're asking configure to generate a Makefile for creating a shared library. And it's always generated even if not used. Since I did not want to use libtool, a tool I don't understand and which comes with that dire warning about C++, this is the primary reason why I use my own Makefiles for e4Graph and only use a Makefile.include that is created by configure, for configuration options. I've never had any issues loading e4Graph shared objects into tclsh or any other executable written in C, C++, even Kylix (Borland Pascal).
Anyways, I've attached the Makefile for e4Graph to show how I link the shared library. Check line 183 or so for the details. There's more examples and a working implementation of using configure only for configuration (as intended) and not also for generating Makefiles, in the distros. (http://sourceforge.net/projects/e4graph).
Jean-Claude Wippler wrote:
I have a question...
For some reason I do not quite understand, MK builds shared libs with "ld". This completes and works as expected with C++ programs, but it causes runtime errors when loaded from a C main (for example Mk4tcl.so loaded from tclsh). It may also breaks down even with C++ in Unix systems which do not support shared library back-linking.
The libtool 1.4.1 info docs sound ominous:
Writing libraries for C++
=========================
Creating libraries of C++ code should be a fairly straightforward
process, because its object files differ from C ones in only three ways:
1. Because of name mangling, C++ libraries are only usable by the C++
compiler that created them. This decision was made by the
designers of C++ in order to protect users from conflicting
implementations of features such as constructors, exception
handling, and RTTI.
2. On some systems, the C++ compiler must take special actions for the
dynamic linker to run dynamic (i.e., run-time) initializers. This
means that we should not call `ld' directly to link such
libraries, and we should use the C++ compiler instead.
3. C++ compilers will link some Standard C++ library in by default,
but libtool does not know which are these libraries, so it cannot
even run the inter-library dependence analyzer to check how to
link it in. Therefore, running `ld' to link a C++ program or
library is deemed to fail. However, running the C++ compiler
directly may lead to problems related with inter-library
dependencies.
The conclusion is that libtool is not ready for general use for C++
libraries. You should avoid any global or static variable
initializations that would cause an "initializer element is not
constant" error if you compiled them with a standard C compiler.
There are other ways of working around this problem, but they are
beyond the scope of this manual.
Furthermore, you'd better find out, at configure time, what are the
C++ Standard libraries that the C++ compiler will link in by default,
and explicitly list them in the link command line. Hopefully, in the
future, libtool will be able to do this job by itself.
My question is: would anyone have a suggestion how to deal with this in the most portable manner? I tend to use MK mostly in static-linked form, but evidently it would be nice to make this work in the most general way possible. The current CVS sources have a "-lstdc++" added to LDFLAGS, which solves it for Linux, but generate the following output on MacOS X (both are gcc 3.1/3.2):
*** Warning: This library needs some functionality provided by -lstdc++.
*** I have the capability to make that library automatically link in when
*** you link to this library. But I can only do this if you have a
*** shared version of the library, which you do not appear to have.
*** The inter-library dependencies that have been dropped here will be
*** automatically added whenever a program is linked with this library
*** or is declared to -dlopen it.
g++ -dynamiclib -flat_namespace -undefined suppress -o .libs/libmk4tcl.dylib mk4tcl.lo mk4too.lo column.lo custom.lo derived.lo fileio.lo field.lo format.lo handler.lo persist.lo remap.lo std.lo store.lo string.lo table.lo univ.lo view.lo viewx.lo -lc -install_name /usr/local/lib/libmk4tcl.dylib
The resulting library does load in tclsh.
Should the conclusion be to throw out libtool altogether? Frankly, I wouldn't mind one bit...
-jcw
_______________________________________________
metakit mailing list - [EMAIL PROTECTED]
http://www.equi4.com/mailman/listinfo/metakit
# makefile -- # # Generic Makefile for building e4Graph on UNIX with GNU C++. # # Author: Jacob Levy, [EMAIL PROTECTED] # # Copyright (c) 2000-2003, JYL Software Inc. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF # JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE.
# Include the parameters determined at configure time:
include ../../all/makefile.include
# Which libraries to link with the libe4graph:
LIBS = -L$(METAKIT_LIB) -lmk4
# The directories containing the source code:
INTF = ../intf
IMPL = ../impl
# The Metakit driver directory:
MKDRV = ../mkdriver
# The directory containing the include files:
INCLUDE = ../include
# What are the sources for e4Graph:
CPPSOURCES = \
$(MKDRV)/mkstorage.cpp \
$(INTF)/e4refcount.cpp \
$(INTF)/e4id.cpp \
$(INTF)/e4node.cpp \
$(INTF)/e4storage.cpp \
$(INTF)/e4vertex.cpp \
$(INTF)/e4nvisitor.cpp \
$(INTF)/e4svisitor.cpp \
$(INTF)/e4vvisitor.cpp \
$(IMPL)/i4drivers.cpp \
${IMPL}/i4dstring.cpp \
$(IMPL)/i4intstack.cpp \
${IMPL}/i4node.cpp \
${IMPL}/i4storage.cpp \
${IMPL}/i4vertex.cpp \
${IMPL}/i4hash.cpp
# What include flags to pass to the compiler:
INCLUDES = \
-I${INCLUDE} -I${MKDRV} -I${METAKIT_INC}
# The object files:
OBJECTS = \
mkstorage.o \
e4refcount.o \
e4id.o \
e4node.o \
e4storage.o \
e4vertex.o \
e4nvisitor.o \
e4svisitor.o \
e4vvisitor.o \
i4dstring.o \
i4drivers.o \
i4intstack.o \
i4node.o \
i4storage.o \
i4vertex.o \
i4hash.o
# What optimization options to pass to the compiler:
CXXFLAGS += $(INCLUDES) -DE4_DLL -DDEBUG
# Main target: makes libe4tree.so:
all: libe4graph.so
# Install the library:
install: all
-@mkdir -p $(includedir)
cp -p ../include/e4graph.h $(includedir)/e4graph.h
-@mkdir -p $(libdir)
cp -p libe4graph.so $(libdir)/libe4graph.so.0.0.0
-@/bin/rm -f $(libdir)/libe4graph.so $(libdir)/libe4graph.so.0
-@ln -s $(libdir)/libe4graph.so.0.0.0 $(libdir)/libe4graph.so
-@ln -s $(libdir)/libe4graph.so.0.0.0 $(libdir)/libe4graph.so.0
# Uninstall the library:
uninstall:
/bin/rm -f $(includedir)/e4graph.h
/bin/rm -f $(libdir)/libe4graph.so.0.0.0
/bin/rm -f $(libdir)/libe4graph.so
/bin/rm -f $(libdir)/libe4graph.so.0
# Release engineering:
release: all
mkdir -p $(release_tmp_dir)/include
cp -p ../include/e4graph.h $(release_tmp_dir)/include/e4graph.h
mkdir -p $(release_tmp_dir)/lib
cp -p libe4graph.so $(release_tmp_dir)/lib/libe4graph.so.0.0.0
cp -p libe4graph.so $(release_tmp_dir)/lib/libe4graph.so
cp -p libe4graph.so $(release_tmp_dir)/lib/libe4graph.so.0
# Individual file targets:
i4hash.o: ${IMPL}/i4hash.cpp
$(CXX) -c $(CXXFLAGS) ${IMPL}/i4hash.cpp
i4drivers.o: ${IMPL}/i4drivers.cpp
$(CXX) -c $(CXXFLAGS) ${IMPL}/i4drivers.cpp
i4dstring.o: ${IMPL}/i4dstring.cpp
$(CXX) -c $(CXXFLAGS) ${IMPL}/i4dstring.cpp
i4intstack.o: ${IMPL}/i4intstack.cpp
$(CXX) -c $(CXXFLAGS) ${IMPL}/i4intstack.cpp
i4vertex.o: ${IMPL}/i4vertex.cpp
$(CXX) -c $(CXXFLAGS) ${IMPL}/i4vertex.cpp
mkstorage.o: ${MKDRV}/mkstorage.cpp
$(CXX) -c $(CXXFLAGS) ${MKDRV}/mkstorage.cpp
i4node.o: ${IMPL}/i4node.cpp
$(CXX) -c $(CXXFLAGS) ${IMPL}/i4node.cpp
i4storage.o: ${IMPL}/i4storage.cpp
$(CXX) -c $(CXXFLAGS) ${IMPL}/i4storage.cpp
e4refcount.o: $(INTF)/e4refcount.cpp
$(CXX) -c $(CXXFLAGS) $(INTF)/e4refcount.cpp
e4id.o: $(INTF)/e4id.cpp
$(CXX) -c $(CXXFLAGS) $(INTF)/e4id.cpp
e4vertex.o: $(INTF)/e4vertex.cpp
$(CXX) -c $(CXXFLAGS) $(INTF)/e4vertex.cpp
e4node.o: $(INTF)/e4node.cpp
$(CXX) -c $(CXXFLAGS) $(INTF)/e4node.cpp
e4storage.o: $(INTF)/e4storage.cpp
$(CXX) -c $(CXXFLAGS) $(INTF)/e4storage.cpp
e4vvisitor.o: $(INTF)/e4vvisitor.cpp
$(CXX) -c $(CXXFLAGS) $(INTF)/e4vvisitor.cpp
e4nvisitor.o: $(INTF)/e4nvisitor.cpp
$(CXX) -c $(CXXFLAGS) $(INTF)/e4nvisitor.cpp
e4svisitor.o: $(INTF)/e4svisitor.cpp
$(CXX) -c $(CXXFLAGS) $(INTF)/e4svisitor.cpp
libe4graph.so: $(OBJECTS)
$(CXX) -shared -o libe4graph.so $(OBJECTS) $(LIBS)
# Clean:
clean:
-@/bin/rm -f ${OBJECTS}
-@/bin/rm -f *~ #*
-@/bin/rm -f libe4graph.so
