Houston, we have an undefined link

MEGAEDIT 3000

I found the reason for the undefined links. I checked the .o files for the characters and they were just missing. It just wasn’t. For no apparent reason. I checked the source of the incriminating .o file, but everything seemed to be OK. I thought this might be one of those nasty #ifdef ... #endif blocks, tricky hidden among lines of code like a bear trap, awaiting their victims. But I could not find. After moving some function definitions to the very end of the file and including them in the #ifdef ... #endif block suitable for Linux, the characters magically appeared, and everything was fine. Thank you for your time.


Out of date, do not read.

Recently, I was assigned one big project, my task is to make it work on Linux platforms. Unfortunately, the programmer who wrote the whole project in front of me did a very poor job of creating a whole batch of circular dependencies, including the B3D_Base.h file, where almost every header is #included , almost every header and source file in the project (which makes 170+ files with line #include "B3D_Base.h" ). This did not cause compilation problems on both Windows and Linux. However, this causes many 'undefined reference' errors during the Linux reference phase, although all object files and libraries are interconnected.

Meaning ld restriction of a single iteration in all object files during linking, I ask:

Is there a way to get ld to do several iterations through objects and libraries, perhaps solving all the supporting errors 700 + undefined, or is this the only chance to link the project by simply replacing all #include "B3D_Base.h" lines with proper inclusion in the necessary headers?

ANNEX No. 1:

Here is an example of what mess I have to do on Linux:

There is one header file B3D_Base.h , to which B3D_Loading3.h added, which contains the class B3D_LOADING3 . The B3D_Loading3.cpp file includes only B3D_Base.h and a memory manager class that is not included in the database. Instance B3D_LOADING3 g_Loading3; declared in B3D_Base.h and initializes +, used in many other parts of the project. Everything compiles just fine, but when it comes to links, I get a lot of 'undefined reference to g_Loading3' . And there are many more such errors, complaining about undefined references to both instances of classes and functions. So much for clean code.

ANNEX No. 2:

I will provide an SSCCE example as kfsone requested:

B3D_Base.h

 ... (many other includes) #include "B3D_Loading3.h" extern B3D_LOADING3 g_Loading3; ... (includes go on) 

B3D_Loading3.h / B3D_Loading.cpp

 a full definition of class B3D_LOADING3, but no real declaration of g_Loading3 

AW_Game.cpp (one of the files that uses g_Loading3)

 #include "B3D_Base.h" ... (some lines) extern B3D_LOADING3 g_Loading3; 

Thanks to kfsone, which made me completely go through the code, I was able to find out what the problem is: g_Loading3 is defined everywhere as extern , therefore it is not detected properly. All I need to do is remove the extern keyword from a single file. Bugs ~ 30 links are fixed. Thanks, kfsone.

ANNEX No. 3:

But the problem with an undefined reference to class functions remains a problem. After some code scanning, I believe that the functions are not even defined due to overuse of the #ifdef ... #endif (portability), and thus this may be my mistake, ignoring functions defined only in some passive ifdef block . I will try to address this issue and then report if something changes.

APPENDIX No. 3 REPORT:

Even after the functions were correctly defined, the undefined-reference list did not decrease. Therefore, the problem remains open for discussion.

ANNEX No. 3.1

I will give an example code.

foo.h

 #ifndef FOO_H #define FOO_H class Foo { unsigned int m_size; bool m_lock; friend class ASDF; public: unsigned int m_id; void Release() {delete this;} int Lock(UINT OffsetToLock, UINT SizeToLock, VOID ** ppbData, DWORD Flags); int Unlock(); }; // other class declarations to follow #endif 

foo.cpp

 #include "Foo.h" // other includes and function definitions to follow int Foo::Lock(UINT OffsetToLock, UINT SizeToLock, VOID ** ppbData, DWORD Flags) { if(!m_lock) { // some locking code } return 0; } 

Bas.cpp

 #include "Foo.h" // although included, defined and declared, causes undef reference Foo *m_pFoo; // several lines later m_pFoo->Lock(0,0,(void)&Asdf,NULL); // <-- compiles fine, causes undefined reference 
+6
source share
3 answers

One thing worth checking out is to determine if it is a problem to remove dead code. Because of this, I had a "undefined link" linker errors.

The MS compiler will delete the code if it is not used. GCC will not do this by default, and if this code uses characters that are not defined, you will get errors. Since the MS compiler removes these calls, you get no errors. To make sure this is your problem, add these flags to your flag compilation (for both C ++ and C, if you also have C sources):

  -fdata-sections -ffunction-sections 

And this flag in your link flags:

  -Wl, - gc-sections 

(Of course, make sure you use g++ for communication, not ld .)

Other than that, my only recommendation is to use the right build system. I highly recommend CMake . It is easy, reliable, and you need to quickly learn it. Creating a CMake-based build for a LOC 300,000 project with over 100 source files took me less than 3 hours (and at that moment I first used CMake.)

+2
source

Without any example, it really is unclear where your problem might be, except that it is not the ordering of the header files - this is what is in these header files, and then the order in which you link the modules.

GCC / LD should only complain about undefined references to things referenced not only by those declared.

 // t1.h #pragma once #include "t2.h" class Foo1 {}; class Foo3 {}; // This is going to be our undef ref extern Foo1 g_foo1_a; extern Foo1& foo1_a(); extern Foo1 g_foo1_b; extern Foo1& foo1_b(); extern Foo2 g_foo2; extern Foo3 g_foo3; // Uncomment this line to generate an undef ref //static Foo3* g_foo3p = &g_foo3; // t2.h #pragma once #include "t1.h" class Foo2 {}; extern Foo2 g_foo2; // t1.cpp #include "t1.h" #include "t2.h" #if defined(_MSC_VER) && _MSC_VER > 9000 Foo3 g_foo3; // gcc won't produce one of these. #endif Foo1& foo1_b() { return g_foo1_b; } int main(int argc, const char** argv) { } // t2.cpp #include "t1.h" Foo1 g_foo1_b; // Makefile all: g++ -Wall -o t1.o -c t1.cpp g++ -Wall -o t2.o -c t2.cpp g++ -Wall -ot t1.o t2.o g++ -Wall -ot t2.o t1.o 

Compiles undef without any links until you uncomment the static information, after which you will get compilation warnings (unused variables) and undefined, since no one actually created an instance of g_foo3.

So - as long as I understand that you cannot give us your exact code, if you want to solve the problem, you probably have to come up with SSCCE . Like not, in the process of replicating the problem you are likely to understand this, so you usually need to ask questions here .

+2
source

On Linux, you'll need a few copies of your -l arguments if you don't want to learn esoteric ld arguments. List all three times three (yes, 3) times:

  -la -lb -lc -la -lb -lc -la -lb -lc 

to ensure that all dependencies between the libraries are met. Please note that the number 3 is independent of the number of libraries. Some versions of ld have -load_all or -( as less detailed solutions to this problem.

The reason is because the linker processes undefined characters from right to left. When he first sees -la , he only picks up the .o files from the liba.a files that are required by the base exec. When he sees -lb , he loads the ones that are required for the base and liba. If libb requires part of liba, you're out of luck if you don't list liba a second time, etc. Etc.

+1
source

Source: https://habr.com/ru/post/949891/


All Articles