Is there an automated program to find C++ linker errors? - c++

I'm working in a Linux environment with C++, using the GCC compiler.
I'm currently working on modifying and upgrading a large pre-existing body of code. As part of this, it has been necessary to add quite a large number of small references throughout the code in a variety of places to link things together, and also to add in several new external code libraries. There is also quite a large and complex structure of Makefiles linked to a configure.ac file to handle the build process.
Upon starting the build process everything compiles without a problem, but comes back with the dreaded linker error when trying to use a newly added custom code library we've created. We have now been through a vast amount of code with a fine tooth comb looking for spelling mismatches, checking the order that all the libraries are included in the build process, and checked that the .o files created contain what we need using dumps, and all are as and where they should be. We've also tested the library separately and the problem definitely doesn't lie there.
In short, we've tried most things that you should normally do in these scenarios.
Is there a tool for C++ that can detect linker errors automatically, in a similar vein to cppcheck or splint (both of which we have run to no avail) that could help here?

Don't know your platform, but I spent sometime with linker problems in gcc till I realized that the static library (.a) linking requires specific ordering, its not the same to link gcc object.o first.a second.a than gcc object.o second.a first.a.

FWIW (not much) I try to tackle this sort of issue by using another linker as I have access to a couple of different platforms. If you can use another linker you will find either:
a) the program links, which transforms your problem from 'why doesn't it link ?' to 'what are the differences between linkers and linking ?' which isn't exactly a step forward, but sometimes a step to one side gives you a different perspective from which you can see a solution;
OR
b) it fails to link, in which case the other linker might give more useful information about why it fails.

Related

Can't compile glew when using it via my own library : CodeLite

I have edited out a lot of my original situation to try keep things simple; it can be seen in the revisions.
Basically I have been following a tutorial in which a game engine is being created.
Most of the code has been separated into its own CodeLite project and successfully compiled into a static library (libbengine.a using mingw32 via TDM-GCC-32).
(For the record, the code compiled fine before separation)
Back in the main game code (main.cpp, etc) the compiler knows the relevant include and lib directories and compilation can at least locate the necessary headers and lib.
However, I get this error: undefined reference to '__glewCreateProgram'
Any ideas as to what is getting lost in translation (so-to-speak)?
I have been reading around all over the place; researching compilation, static libraries, ar.exe, but am having no luck (I am still looking).
If you want any more pertinent information, I will happily provide it; for now I shan't clog up the post any further.
Cheers
To give a basic idea of the error in CodeLite:
Main project linker settings:
bengine project linker settings (compiled as static lib.a):
It seems the problem was solely with linking order. As can be seen in the second image in my question (Main linker setting) - "Bengine" should have been at the top of the list, not the bottom.
This may be mingw32 specific; I am not sure.
Well, after all those hours, I feel somewhat foolish...
At least I have learned some things along the way.

Why would a C program compile and link with a C compiler against C++ libraries then SIGILL at runtime?

I recently had a problem with a 3rd party plugin that I wrote on IBM AIX. It took considerable time to track down. The plugin was in the form of a C executable. The executable was compiled against 3rd party libraries. A new version of those libraries was provided for a mandatory upgrade.
When compiled and linked with the IBM C compiler 12.1 my existing code would produce a binary that would work if the timezone was set using OLSON and crash with SIGILL and no backtrace available if the timezone was set using POSIX.
I was able to track down the crash to a call to the 3rd party API fairly quickly using debug printfs to a log file and flushing the log file. But it took some time for the 3rd party provider to mention that the new version of the API introduced the use of C++ libraries in their own code.
The problem was resolved by compiling with the IBM C compiler but linking with the IBM C++ linker (xlC).
So my questions are:
1) Why didn't the C linker fail to produce a valid executable?
A semi-valid binary must have been produced or the code would not have worked under OLSON timezone. That means all the symbols were present and any name mangling was handled (though possibly not correctly)
2) How do I determine if the binary produced by compiler and linker is valid?
The only way I can think to do this is to fully excercise the code as much as possible with unit testing.
3) How do I prevent similar from occuring for different code?
Should I always link with a C++ linker? That doesn't seem right to me.
I apologize that I can't post code, but I am not at liberty to do this.
Zsigmond has a lot of good statements. We need at least to see the link line and its options to help you much. Very often, open source links with "ignore unresolved symbols" because they don't understand the import files. So, the link will succeed in producing an utterly useless binary -- cause that is why it was asked to do.

gcc compiler linking differently on two servers

I have a large source-controlled C++ codebase which compiles and links without error on one Linux server.
I am now trying to set up the same application on a new server, so have checked out the same code on a new box.
However, when I execute an identical make command on identical code on this new box, I get errors. The cause appears to be because on the old box, shared library (.so) files are created. On the new box - which is using identical code and therefore makefiles - makes static libraries (.a).
The compiler being used appears to be the same as well - gcc-3.4.6.
Obviously, I have some config set differently somewhere but can anyone advise or where this config might be? I can't think of any small change which would cause this effect.
Note that the linker ld is part of binutils, which is delivered with the standard binaries as part of the Unix distribution you have, and is not part of the gcc suite.
Therefore, when you get from an old server to a new server, chances are that you pass from an old ld to a new ld.
Since a library is first created by the linker, it would be interested to check it out.
Note that if you suspect the compiler (since it performs the call to ld), you can write a ld executable script that just echoes the arguments it receives and then calls the real ld behind the scenes (meddling with $PATH should get you going).
It sounds natural that it is either a case of different arguments (why ?) or a different binray, figure out which and you'll be one step closer to solving your issue.
configure stuff might have generated slightly different Makefile-s.
And when you link with -lfoo, the linker first try dynamic libfoo.so then static libfoo.a.
GCC is now at version 4.6.2 so your 3.4.6 version is very old. Consider upgrading it, because GCC has made a lot of progress since.
Try using gcc -v (perhaps as make CC='gcc -v') to understand what is going on when building.
And give much more detail if you want real help. What are the actual libraries involved?

Can I ask VC++ linker to ignore unresolved externals?

I'm trying to build a very complex open-source project with VC++. The project consists of dozens of libraries and one executable depending on those libraries.
For some reasons VC++ linker doesn't want to see about 40 functions implemented in one of those libraries and reports "unresolved external reference" on each, so I can't link. I don't want to waste time resolving the problem - those functions are likely never called.
I'd like to just ask the linker to link what it sees and insert some reasonable error handling (like reporting an error and terminating the program) instead of missing functions. How can I do that?
You can use the /FORCE:UNRESOLVED linker option.
The documentation for that contains the rather understated warning:
A file created with this option may
not run as expected.
In pratice, there'll be no error handling - just a crash.
If the functions are truly never called, then create actual libraries (.lib files) for the libraries. Then the linker will only extract from the libraries what's needed.
The linker's job is to resolve all references, so I don't think you're going to get it to insert error handling code.
P.S. The first thing I'd check is to see if C functions got compiled as C++, leading to the missing symbols.
If they're never called, remove the references from your project. If they are called, then fix the damn problem. There's no real other option here.
There are some notable exceptions, but most OpenSource projects are not designed to be built under VisualStudio.
Generally for a Windows port you are better off using either cygwin or the mingw system. My advice is usually for mingw, unless the program uses a lot of Unix OSey calls like pipes and signals.

Adding Boost makes Debug build depend on "non-D" MSVC runtime DLLs

I have an annoying problem which I might be able to somehow circumvent, but on the other hand would much rather be on top of it and understand what exactly is going on, since it looks like this stuff is really here to stay.
Here's the story: I have a simple OpenGL app which works fine: never a major problem in compiling, linking, or running it. Now I decided to try to move some of the more intensive calculations into a worker thread, in order to possibly make the GUI even more responsive — using Boost.Thread, of course.
In short, if I add the following fragment in the beginning of my .cpp file:
#include <boost/thread/thread.hpp>
void dummyThreadFun() { while (1); }
boost::thread p(dummyThreadFun);
, then I start getting "This application has failed to start because MSVCP90.dll was not found" when trying to launch the Debug build. (Release mode works ok.)
Now looking at the executable using the Dependency Walker, who also does not find this DLL (which is expected I guess), I could see that we are looking for it in order to be able to call the following functions:
?max#?$numeric_limits#K#std##SAKXZ
?max#?$numeric_limits#_J#std##SA_JXZ
?min#?$numeric_limits#K#std##SAKXZ
?min#?$numeric_limits#_J#std##SA_JXZ
Next, I tried to convert every instance of min and max to use macros instead, but probably couldn't find all references to them, as this did not help. (I'm using some external libraries for which I don't have the source code available. But even if I could do this — I don't think it's the right way really.)
So, my questions — I guess — are:
Why do we look for a non-debug DLL even though working with the debug build?
What is the correct way to fix the problem? Or even a quick-and-dirty one?
I had this first in a pretty much vanilla installation of Visual Studio 2008. Then tried installing the Feature Pack and SP1, but they didn't help either. Of course also tried to Rebuild several times.
I am using prebuilt binaries for Boost (v1.36.0). This is not the first time I use Boost in this project, but it may be the first time that I use a part that is based on a separate source.
Disabling incremental linking doesn't help. The fact that the program is OpenGL doesn't seem to be relevant either — I got a similar issue when adding the same three lines of code into a simple console program (but there it was complaining about MSVCR90.dll and _mkdir, and when I replaced the latter with boost::create_directory, the problem went away!!). And it's really just removing or adding those three lines that makes the program run ok, or not run at all, respectively.
I can't say I understand Side-by-Side (don't even know if this is related but that's what I assume for now), and to be honest, I am not super-interested either — as long as I can just build, debug and deploy my app...
Edit 1: While trying to build a stripped-down example that anyway reproduces the problem, I have discovered that the issue has to do with the Spread Toolkit, the use of which is a factor common to all my programs having this problem. (However, I never had this before starting to link in the Boost stuff.)
I have now come up with a minimal program that lets me reproduce the issue. It consists of two compilation units, A.cpp and B.cpp.
A.cpp:
#include "sp.h"
int main(int argc, char* argv[])
{
mailbox mbox = -1;
SP_join(mbox, "foo");
return 0;
}
B.cpp:
#include <boost/filesystem.hpp>
Some observations:
If I comment out the line SP_join of A.cpp, the problem goes away.
If I comment out the single line of B.cpp, the problem goes away.
If I move or copy B.cpp's single line to the beginning or end of A.cpp, the problem goes away.
(In scenarios 2 and 3, the program crashes when calling SP_join, but that's just because the mailbox is not valid... this has nothing to do with the issue at hand.)
In addition, Spread's core library is linked in, and that's surely part of the answer to my question #1, since there's no debug build of that lib in my system.
Currently, I'm trying to come up with something that'd make it possible to reproduce the issue in another environment. (Even though I will be quite surprised if it actually can be repeated outside my premises...)
Edit 2: Ok, so here we now have a package using which I was able to reproduce the issue on an almost vanilla installation of WinXP32 + VS2008 + Boost 1.36.0 (still pre-built binaries from BoostPro Computing).
The culprit is surely the Spread lib, my build of which somehow requires a rather archaic version of STLPort for MSVC 6! Nevertheless, I still find the symptoms relatively amusing. Also, it would be nice to hear if you can actually reproduce the issue — including scenarios 1-3 above. The package is quite small, and it should contain all the necessary pieces.
As it turns out, the issue did not really have anything to do with Boost.Thread specifically, as this example now uses the Boost Filesystem library. Additionally, it now complains about MSVCR90.dll, not P as previously.
Boost.Thread has quite a few possible build combinations in order to try and cater for all the differences in linking scenarios possible with MSVC. Firstly, you can either link statically to Boost.Thread, or link to Boost.Thread in a separate DLL. You can then link to the DLL version of the MSVC runtime, or the static library runtime. Finally, you can link to the debug runtime or the release runtime.
The Boost.Thread headers try and auto-detect the build scenario using the predefined macros that the compiler generates. In order to link against the version that uses the debug runtime you need to have _DEBUG defined. This is automatically defined by the /MD and /MDd compiler switches, so it should be OK, but your problem description suggests otherwise.
Where did you get the pre-built binaries from? Are you explicitly selecting a library in your project settings, or are you letting the auto-link mechanism select the appropriate .lib file?
I believe I have had this same problem with Boost in the past. From my understanding it happens because the Boost headers use a preprocessor instruction to link against the proper lib. If your debug and release libraries are in the same folder and have different names the "auto-link" feature will not work properly.
What I have done is define BOOST_ALL_NO_LIB for my project(which prevents the headers from "auto linking") and then use the VC project settings to link against the correct libraries.
Looks like other people have answered the Boost side of the issue. Here's a bit of background info on the MSVC side of things, that may save further headache.
There are 4 versions of the C (and C++) runtimes possible:
/MT: libcmt.lib (C), libcpmt.lib (C++)
/MTd: libcmtd.lib, libcpmtd.lib
/MD: msvcrt.lib, msvcprt.lib
/MDd: msvcrtd.lib, msvcprtd.lib
The DLL versions still require linking to that static lib (which somehow does all of the setup to link to the DLL at runtime - I don't know the details). Notice in all cases debug version has the d suffix. The C runtime uses the c infix, and the C++ runtime uses the cp infix. See the pattern? In any application, you should only ever link to the libraries in one of those rows.
Sometimes (as in your case), you find yourself linking to someone else's static library that is configured to use the wrong version of the C or C++ runtimes (via the awfully annoying #pragma comment(lib)). You can detect this by turning your linker verbosity way up, but it's a real PITA to hunt for. The "kill a rodent with a bazooka" solution is to use the /nodefaultlib:... linker setting to rule out the 6 C and C++ libraries that you know you don't need. I've used this in the past without problem, but I'm not positive it'll always work... maybe someone will come out of the woodwork telling me how this "solution" may cause your program to eat babies on Tuesday afternoons.
This is a classic link error. It looks like you're linking to a Boost DLL that itself links to the wrong C++ runtime (there's also this page, do a text search for "threads"). It also looks like the boost::posix::time library links to the correct DLL.
Unfortunately, I'm not finding the page that discusses how to pick the correctly-built Boost DLL (although I did find a three-year-old email that seems to point to BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB).
Looking at your answer again, it appears you're using pre-built binaries. The DLL you're not able to link to is part of the TR1 feature pack (second question on that page). That feature pack is available on Microsoft's website. Or you'll need a different binary to link against. Apparently the boost::posix::time library links against the unpatched C++ runtime.
Since you've already applied the feature pack, I think the next step I would take would be to build Boost by hand. That's the path I've always taken, and it's very simple: download the BJam binary, and run the Boost Build script in the library source. That's it.
Now this got even a bit more interesting... If I just add this somewhere in the source:
boost::posix_time::ptime pt = boost::posix_time::microsec_clock::universal_time();
(together with the corresponding #include stuff), then it again works ok. So this is one quick and not even too dirty solution, but hey — what's going on here, really?
From memory various parts of the boost libraries need you to define some preprocessor flags in order to be able to compile correctly. Stuff like BOOST_THREAD_USE_DLL and so on.
The BOOST_THREAD_USE_DLL won't be what's causing this particular error, but it may be expecting you to define _DEBUG or something like that. I remember a few years ago in our boost C++ projects we had quite a few extra BOOST_XYZ preprocessor definitions declared in the visual studio compiler options (or makefile)
Check the config.hpp file in the boost thread directory. When you pull in the ptime stuff it's possibly including a different config.hpp file, which may then define those preprocessor things differently.