Link to home
Start Free TrialLog in
Avatar of daveburrow
daveburrowFlag for United States of America

asked on

Nested libraries -- linker error

All,

I'm new to developing in gcc, ultimately for cross platform targets, and have hit a bump on trying to modularize my first bits of code.... I'm fairly motivated to get this going as I'm trying to set development standards for such endevors.  

Here's my draft attempt at defining the problem consisely.... TIA!

Scenerio (obsfucated):

I'm trying to break apart the code into what would seem to me to be logical, reusable libraries. Generally:
-- Library "first" is the most commonly called functions, intended as common to all my future projects
-- Library "second" makes use of the functions of library "first" and adds functions common to a few of my projects
-- Executable "third" also makes use of the functions of library "first", and functions of library "second"

Project "First" (static library)
libfirst.a contains some common logging functions, as generated by:
   first.c (function definitions)
   first.h (standard #includes/#definitions/function prototype declarations)
   ==> and where the function prototype declarations have been given "extern" storage class

Project "Second" (static library)
libsecond.a contains some common functions for a handful of projects, as generated by:
   second.c (function definitions, includes calls to logging functions in first.a)
   second.h (standard #includes/ ==> #include first.h <==/#definitions/function prototype declarations)

Project "Third" (executable)
third.exe will not link for reasons described below, and has files:
   third.c (function definitions -- including main(), includes calls to logging functions from first.a)
   third.h (standard #includes/==> #include second.h <==)


1) The first.a library compiles and archives successfully.  Issuing a:
#nm libfirst.a
produces the expected results... listing "first.o" as it's only member, followed by the standard and user-defined functions defined or used by first.c

2) The second.a library compiles and archives successfully. Issuing a:
#nm libsecond.a
produces a listing that lists second.o as it only member.  The standard and user-defined functions from first.c and second.c follow.

3) Compiling third.c/third.h compiles successfully.  In the link phase, the output contains entries such as:

#C:\cygwin\usr\local\lib/libfedmq.a(fedmq.o): In function `TraceDump':
#/usr/local/include/ifscommon.h:267: multiple definition of `_TraceDump'
#./fedmqmonitor.o:/usr/local/include/ifscommon.h:267: first defined here

Notes:

The development environment (IDE) is the CDT plugin for Eclipse, running under Cygwin.

The libfirst.a was:
   - generated using the CDT "Managed Make C Project"
   - has a project type "Static Library (Gnu on Windows)"

The libsecond.a was:
   - generated using the CDT "Managed Make C Project"
   - has a project type "Static Library (Gnu on Windows)"

The third.exe was:
   - generated using the CDT "Managed Make C Project"
   - has a project type "Executable (Gnu on Windows)"

Third.exe produces the same link errors if both first.h and second.h are included, there is no difference.


Questions:

1) Is the libsecond.a file supposed to have the functions of libfirst.a? That is, libfirst.a has 'extern'ed functions, should the archiver ("ar -r") have included them in libsecond.a?

2) Why is the duplicate function error not at issue when generating the libsecond.a project? That is, does the archiver check for duplicates as the linker does?

3) Ultimately:
===> What is the "right" way to structure and manage such a scenerio of nested libraries?
===> What is best practice?
===> What traps/pitfalls are there to using "nested" libraries (one library calling another)?




Avatar of rajeev_devin
rajeev_devin

>> #/usr/local/include/ifscommon.h:267: multiple definition of `_TraceDump'
This is not a linker error.
It is compilation error.
>> This is not a linker error.
sorry. I din't read the question.
it is a linker error.
first is a static library.
second is a static library.

and you are linking them to third
seems ok to me.
Avatar of sunnycoder
Did you protect against mulitple inclusion? Each of your .h files should be structured like as shown below

#ifndef FIRST_H
#ifdef FIRST_H
//header file contents here
#endif /*FIRST_H -> this name would be unique for each header file in the project*/
Avatar of daveburrow

ASKER

yessir --- all .h files are so protected.... (as generated by the CDT IDE on file creation) and appear to be correct.
1. What was the exact command line for compiling the third library
Since all libraries are statically linked, it might so happen that second.o included a definition of function defined in first.o ... If third.o was linked to first.o and second.o, there would be multiple definitions of functions in first.o ... try compiling all .c files on a single command line instead on linking the .a files. Does that work?

2. Make sure that you are defining the TraceDump function only once - name should not be repeated in any of the files.
sunnycoder:

Thanks for the quick responses.... here's more verbose output.... :-)

To your previous "1." -- see the console outputs below. All .c files compile fine, just the link of the last output fails
To your previous "2." -- All functions are uniquely named across all three projects.

At the risk of logging ==>too<== much, I'm including the console output of the three project builds..... I can't expect help on limited information.

Where:
Project "first" is actually named "ifscommon"
Project "second" is actually named "fedmq"
Project "third" is actually named "MQMonitor"

To help understand the console outputs, please be aware that the "make" starts in the Debug folder of each project:

$(workspace_root)
     |
     |-> ifscommon
     |          |
     |          |-> Debug
     |          |         |-> makefile
     |          |-> ifscommon.c
     |          |-> ifscommon.h
     |
     |-> fedmq
     |          |
     |          |-> Debug
     |          |         |-> makefile
     |          |-> fedmq.c
     |          |-> fedmq.h
     |
     |-> MQMonitor
                |
                |-> Debug
                |         |-> makefile
                |-> MQMonitor.c
                |-> MQMonitor.h




Project "ifscommon" output......
==========================================================================
**** Full rebuild of configuration Debug for project ifscommon ****

make -k clean all
rm -rf  ./ifscommon.o  ./ifscommon.d libifscommon.a
 
Building file: ../ifscommon.c
Invoking: GCC C Compiler
gcc -I.. -O0 -g3 -Wall -c -fmessage-length=0 -std=c99 -oifscommon.o ../ifscommon.c
Finished building: ../ifscommon.c
 
Building target: libifscommon.a
Invoking: GCC Archiver
ar -r libifscommon.a ./ifscommon.o
ar: creating libifscommon.a
Finished building target: libifscommon.a
 
Build complete for project ifscommon
==========================================================================




Project "fedmq" output......
==========================================================================
**** Full rebuild of configuration Debug for project fedmq ****

make -k clean all
rm -rf  ./fedmq.o  ./fedmq.d libfedmq.a
 
Building file: ../fedmq.c
Invoking: GCC C Compiler
gcc -I.. -IC:\cygwin\usr\local\include -IC:\cygwin\usr\include -IC:\Program Files\IBM\WebSphere MQ\Tools\c\include -O0 -g3 -c -fmessage-length=0 -std=c99 -ofedmq.o ../fedmq.c
Finished building: ../fedmq.c
 
Building target: libfedmq.a
Invoking: GCC Archiver
ar -r libfedmq.a ./fedmq.o
ar: creating libfedmq.a
Finished building target: libfedmq.a
 
Build complete for project fedmq
==========================================================================



Project "MQMonitor" output......
==========================================================================
**** Full rebuild of configuration Debug for project MQMonitor ****

make -k clean all
rm -rf  ./fedmqmonitor.o  ./fedmqmonitor.d MQMonitor.exe
 
Building file: ../fedmqmonitor.c
Invoking: GCC C Compiler
gcc -I.. -IC:\Program Files\IBM\WebSphere MQ\Tools\c\include -O0 -g3 -Wall -c -fmessage-length=0 -std=c99 -ofedmqmonitor.o ../fedmqmonitor.c
Finished building: ../fedmqmonitor.c
 
Building target: MQMonitor.exe
Invoking: GCC C Linker
gcc -LC:\cygwin\usr\local\lib -LC:\Program Files\IBM\WebSphere MQ\Tools\Lib -oMQMonitor.exe ./fedmqmonitor.o -lpopt -lfedmq -lsqlite3 -lmqm
C:\cygwin\usr\local\lib/libfedmq.a(fedmq.o): In function `setTraceThreshold':
/usr/local/include/ifscommon.h:32: multiple definition of `_setTraceThreshold'
./fedmqmonitor.o:/usr/local/include/ifscommon.h:32: first defined here
C:\cygwin\usr\local\lib/libfedmq.a(fedmq.o): In function `TraceDump':
/usr/local/include/ifscommon.h:267: multiple definition of `_TraceDump'
./fedmqmonitor.o:/usr/local/include/ifscommon.h:267: first defined here
C:\cygwin\usr\local\lib/libfedmq.a(fedmq.o): In function `fDumpWrite':
/usr/local/include/ifscommon.h:311: multiple definition of `_fDumpWrite'
./fedmqmonitor.o:/usr/local/include/ifscommon.h:311: first defined here
C:\cygwin\usr\local\lib/libfedmq.a(fedmq.o): In function `fDumpRead':
/usr/local/include/ifscommon.h:358: multiple definition of `_fDumpRead'
./fedmqmonitor.o:/usr/local/include/ifscommon.h:358: first defined here
C:\cygwin\usr\local\lib/libfedmq.a(fedmq.o): In function `TraceLine':
/usr/local/include/ifscommon.h:223: multiple definition of `_TraceLine'
./fedmqmonitor.o:/usr/local/include/ifscommon.h:223: first defined here
collect2: ld returned 1 exit status
make: *** [MQMonitor.exe] Error 1
make: Target `all' not remade because of errors.
Build complete for project MQMonitor
==========================================================================




ASKER CERTIFIED SOLUTION
Avatar of cwwkie
cwwkie

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

OK, so there's a big problem --- and one I missed entirely --- ifscommon.h has only 33 lines in the Project Folder.

So poking around I found that I had not exported the Project File version of ifscommon.h to "/usr/local/include",  so the include directory for the build of fedmq.c/.h was an old version that had far too many lines in it, of course including definitions.

Very good catch.... Thank-you!

So more info:  Having not be brought up in the c/c++ culture, after I had complied each project, I exported the .h file of each project to "/usr/local/include", so that I could use the angle bracket syntax (#include <header.h>) instead of the quoted syntax (#include "header.h").  

I just missed the export of one of the files.

All projects compile and link successfully now.  Thanks again!


> so that I could use the angle bracket syntax (#include <header.h>) instead of the quoted syntax (#include "header.h").  

There is nothing wrong with the quoted syntax. If might even be easier to recognise your own header files.
But if you want to copy files around, you can consider including that in the makefile.