1

I asked the same question yesterday and the answer was not applicable.

https://stackoverflow.com/questions/6194578/breaking-up-class-functions-into-multiple-cpp-files

If I go into the class header, right click on the function and click "Go to Definition" and it takes me right to my function in my other .CPP file. It sees it, can link to it and still I get errors that indicate I cannot see it.

Anyone have any suggestions? I'll try anything.

Here is the error again.

zdll.lib(d000050.o) : warning LNK4078: multiple '.text' sections found with different attributes (E0300020)

WLD.obj : error LNK2019: unresolved external symbol "public: void __thiscall WLD::fragment_03(unsigned char *,int)" (?fragment_03@WLD@@QAEXPAEH@Z) referenced in function "public: bool __thiscall WLD::init(unsigned char *)" (?init@WLD@@QAE_NPAE@Z)

Edit: Also, I am using MSVC++. Should I try creating a new solution and importing the files? May help as I feel I am out of options...

Edit: Here is the code:

#include "WLD.h"

inline void WLD::fragment_03(uchar* location, int frag_num)
{
    // Read the struct into memory and create a temporary pointer
    struct_frag03 temp03;
    memcpy(&temp03, location, sizeof(struct_frag03));
    uchar* temp_p = location;

    // Advance the pointer to the encoded bytes (filename)
    temp_p += sizeof(long) + sizeof(short);

    // Grab the encoded filename and decode it
    uchar* f_filename = new uchar [sizeof(temp03.nameLen + 1)];
    memcpy(f_filename, temp_p, temp03.nameLen + 1);
    decode(f_filename, temp03.nameLen);

    // Add the details about this bitmap to the array
    bmp_array[current_bmp].filename = f_filename;
    bmp_array[current_bmp].nameLength = temp03.nameLen;
    bmp_array[current_bmp].reference03 = frag_num;

    // 0x03 Debug
    //errorLog.OutputSuccess("0x03 Filename: %s", bmp_array[current_bmp].filename);
    //errorLog.OutputSuccess("0x03 Name length: %i",bmp_array[current_bmp].nameLength);
    //errorLog.OutputSuccess("0x03 Reference: %i", bmp_array[current_bmp].reference03);

    // Add the bitmap to the count
    current_bmp++;
}

And here is where the code is called in the WLD class:

case 0x03:
    fragment_03(wld + file_pos + sizeof(struct_wld_basic_frag), i);
    break;

Here is the header file declaration: in (WLD.h):

public:
    inline void fragment_03(uchar* location, int frag_num);
Community
  • 1
  • 1
Pladnius Brooks
  • 1,248
  • 3
  • 19
  • 36
  • It would help if you'd put the declaration and implementation of `WLD::fragment_03` and the portion of `WLD::init` where it is called. – littleadv Jun 01 '11 at 23:48
  • Hard to diagnose things without code... – Billy ONeal Jun 01 '11 at 23:48
  • Would also be good to know what compiler/linkers you're using... – forsvarir Jun 01 '11 at 23:50
  • 1
    The answer to your prior question was very applicable. An unresolved external is a linker error, which the other answer told you. Voting to close - if you have issues with the other question or it's answer, edit it to provide more information or post comments to other answers there. – Ken White Jun 01 '11 at 23:51
  • @Billy ONeal I added the code – Pladnius Brooks Jun 01 '11 at 23:55
  • Your edit would be more helpful if you also showed your commandline call to the compiler/linker, as well as indicated what compiler you're using. As you've been told, this is a **linker error**, but you're not showing what information you're providing to the **linker**. – Ken White Jun 01 '11 at 23:57
  • @Ken White I added a lot more information. – Pladnius Brooks Jun 01 '11 at 23:57
  • 1
    @Judas : Have you tried not marking the definition as `inline`? – ildjarn Jun 01 '11 at 23:57
  • @Ken As indicated above and in a comment I am using MSVC++ 2010. Also, I don't know what command line call I am sending to the compiler/linked. I am just building the solution. – Pladnius Brooks Jun 01 '11 at 23:58
  • @ildjarn Thank you!!! This was the issue. I am curious as to why though. – Pladnius Brooks Jun 01 '11 at 23:59
  • @Judas : Billy beat me to it by 1 second, and with an explanation. ;-] – ildjarn Jun 02 '11 at 00:03
  • @judas - asking the same question again just because you didn't like the answer (or get enough answers) is bad SO etiquette and attracts flags. You should have updated the original question with further clarifications which would have bumped the question: http://meta.stackexchange.com/questions/7046/how-to-get-attention-for-your-old-unanswered-questions . Please don't do this. Thanks. – Kev Jun 02 '11 at 11:42

2 Answers2

7

inline means that the function effectively has internal linkage (that is, it must exist inside the translation unit where it is used). Either move the definition of the function into the header, or remove inline.

(inline for modern compilers really means "use internal linkage" -- compilers will inline where it makes sense to by themselves, and they typically make better decisions than humans)

EDIT: Technically speaking, the language the standard uses here says that inline functions have external linkage; however, it also says An inline function shall be defined in every translation unit in which it is used. in section 3.2 paragraph #3 of the standard, and also There can be more than one definition of a ... inline function with external linkage (7.1.2) ... Given such an entity named D defined in more than one translation unit ... each definition of D shall consist of the same sequence of tokens in paragraph 5. So while technically speaking the name you declared inline is accessible from outside a given translation unit, to do so is to cause undefined behavior from C++.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • Thank you. You and forsvarir had the correct answer and thank you for the explanation!!! – Pladnius Brooks Jun 02 '11 at 00:00
  • Not correct, `static` functions have internal linkage. `inline` functions, by default just like any other function, have `extern`al linkage. At linking step all duplicate `inline`d instances of function are dropped by the linker. If you have different files that have different `inline` functions with the same signature then you will see that only one will actually be called from different files. – Pavel P Feb 14 '12 at 04:42
  • @Pavel: The same holds true for `static` on most compilers. Removal of the duplicate entries is a non-required optimization (MSVC++ calls it COMDAT folding, I don't know what GCC _ others call it....) – Billy ONeal Feb 14 '12 at 15:17
  • COMDAT is different. It's elimination of unreferenced functions/data at link time. Whether it was removed or not, doesn't make any difference in that case: with multiple inline function defined in different files linker will chose only one of them. If you simply define multiple functions in different files without inline you'll get link errors (multiple defined symbols). – Pavel P Feb 14 '12 at 19:00
  • I agree, that there might be compiler defined behavior there, I simply tested my knowledge and MS compiler works the way I expected. I didn't try it with gcc though. In short, "inline vs static" is an interesting subject: there are also differences of static variables declared inside them etc etc. – Pavel P Feb 14 '12 at 19:02
  • @Pavel: Of course, for *variables* the above does not apply; I'm speaking about functions only. COMDAT is folding identical assembly bits together so that e.g. `vector` and `vector` don't cause the binary size to double if `int` and `long` are the same on a given platform. It has nothing to do with unreferenced data. – Billy ONeal Feb 15 '12 at 14:59
  • Billy, I guess it's enough discussion. COMDAT is something similar to function-sections cmd line switch in gcc and it's a linker thing. Linker doesn't know difference between data/functions, it deals with symbols and dependencies. Anyways, back to my original post. To prove that you are completely wrong (read your original comment) you can test these files: http://pastebin.com/bmt0ccSB gcc compilation: `gcc test1.cpp test2.cpp test_inline.cpp -o test_inline`. If you were correct you'd get a link error, but you don't get it because inline function is external in fact. – Pavel P Feb 16 '12 at 03:39
  • 1
    @Pavel: Your example exhibits undefined behavior, and therefore any behavior, including "just works" on a particular toolchain is okay. The standard says `An inline function shall be defined in every translation unit in which it is used.` in section 3.2 paragraph 3 of C++03 and C++11. – Billy ONeal Feb 16 '12 at 03:46
  • in short that test in two separate file has two different inline functions with the same signature. Then, main calls them without any issues, plus main calls functions from these test1.cpp and test2.cpp, but resulting output will show that only one of them exists in the binary. So far MS compiler and GCC proved that I'm right. – Pavel P Feb 16 '12 at 03:46
  • 1
    @Pavel: Upon checking, yes, in fact the default linkage as far as the standard is concerned for inline functions is still external. However, the rule I quoted in the previous comment makes it irrelevant. – Billy ONeal Feb 16 '12 at 03:48
  • 1
    @Pavel: Compilers can never prove you right. Only the standard can do that. – Billy ONeal Feb 16 '12 at 03:49
  • well, that undefined behavior is that linker will silently choose only one of them and it's undefined which one of them. If it was internal linkage you wouldn't get any of the problems, and wouldn't have undefined behavior. Replace inline with static and you get compilation error, remove call to test(123) from main and you get expected output. – Pavel P Feb 16 '12 at 03:49
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/7774/discussion-between-pavel-and-billy-oneal) – Pavel P Feb 16 '12 at 03:49
  • 1
    @Pavel: Then you violated the ODR. I don't see how that matters. – Billy ONeal Feb 16 '12 at 03:52
  • There is no point to say that my example has undefined behavior. I'm sure you saw that inlines are external by default, that's what matters and that simple example was to prove my claim. – Pavel P Feb 16 '12 at 04:05
  • 1
    @Pavel: No, it doesn't. Only the standard can prove your claim, and you didn't cite the standard anywhere. There are plenty of things that are bugs that are implemented in buggy ways by both MSVC++ and GCC. (e.g. requiring use of `this` in some kinds of template situations) – Billy ONeal Feb 17 '12 at 02:27
6

This has nothing to do with includes. What you have there is a linker error. Includes are all about compilation, which requires the declarations of identifiers referred to.
The error you have means that the linker can't find the definition of a function in any of the object files passed to it which is called by one or more of them. (See this answer for what's a declaration and what's a definition and what they are needed for.)

You need to pass to the linker the object files created from compiling all of your .cpp files. If you're using some sort of an IDE, it should do this for you if you add all .cpp files to your project. If you're using a makefile, list all .cpp files as dependencies of your target. If you compile by invoking the compiler manually (which then calls the linker), pass all .cpp files to it in the same invocation.

Community
  • 1
  • 1
sbi
  • 219,715
  • 46
  • 258
  • 445