?
Solved

LNK2019: unresolved external symbol

Posted on 2007-08-12
25
Medium Priority
?
895 Views
Last Modified: 2013-12-14
I always get LNK2019, I'm very talented at finding new ways to generate that error. This time I outdid myself because I haven't been able to figure out how to fix it.

LNK2019: unresolved external symbol _backup_block referenced in function _fil_write      innobase.lib
(Visual Studio 2005)

In backup.h the prototype is:

int backup_block(int, int, int, char* );

In backup.c the definition is:

int backup_block(int arg0, int arg1, int arg2, char* arg3) {       

The project settings are compile as C++ code, and I don't see any extern "C" anywhere so I think it is all C++ code. backup.c is also C++ code. I can tell it is being compiled by looking at the output, but I have no idea why the linker can't find the function.

I'm out of ideas to try. I'm sure it must be something simple but it escapes me. I've not used C++ for too long I think :)

Thanks,
-Sandra
0
Comment
Question by:Sandra-24
  • 6
  • 6
  • 5
  • +3
25 Comments
 
LVL 13

Expert Comment

by:josgood
ID: 19679578
Could this be a name decoration issue?

I notice the unresolved symbol has a leading underscore.


0
 
LVL 3

Author Comment

by:Sandra-24
ID: 19679600
Could be, why does it have that? Neither backup_block or fil_write have leading underscores so the compiler must be adding them.
0
 
LVL 13

Expert Comment

by:josgood
ID: 19679629
There used to be a option that controlled this.  I can't quickly find it in VS2005, but I'm sure it is still there somewhere.

Are other symbols in the link map prefixed with underscore?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 86

Expert Comment

by:jkr
ID: 19679646
The underscore is common for all functions delcared as '__cdecl'. Try adding that keyword to the declaration, e.g.

int __cdecl backup_block(int, int, int, char* );
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 19679824
josgood: I bet they are, if fil_write is prefixed with an underscore there must be hundreds of others (maybe all even) but I don't know where to check to verify that.

jkr: I tried that, same thing.

Still baffled by this

-Sandra
0
 
LVL 13

Expert Comment

by:josgood
ID: 19679896
In the solution properties,
Configuration Properties | C/C++ | Advanced
is "Compile As" set to default?

If so, I suggest setting it to "Compile as C++ code"

That may correct the problem.

If not, you could try creating a new solution that contains only fil_write and backup.c.  See if the problem exists in the new solution, or not.
0
 
LVL 4

Expert Comment

by:dragulj
ID: 19680156
Error you get is because your function is compiled using C rules. Putting __cdecl won't change anything. Either try to force C++ compilation or try to declare your function as a C function as follows:

extern "C" backup_block (int, int, int, char *);

Try also the simplest way: rename all your *.c source to *.cpp without any other change inside the source.
0
 
LVL 4

Expert Comment

by:dragulj
ID: 19680163
Just one important thing more: extern "C" should be used in a function definition, not declaration.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 19681523
I agree with dugulj.

Write your functions as:

extern "C" int backup_block(int arg0, int arg1, int arg2, char* arg3) {

    // ...

}

0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 19682291
>>>> rename all your *.c source to *.cpp

Yes, dragulj is right. VC compilers will compile .c files with C rules (no name mangling) but the linker may expect C++ name syntax (or vice versa). If it is C++ code actually you should consider renaming the .c in .cpp rather than using extern "C" which is for integrating C code.

>>>> I suggest setting it to "Compile as C++ code"
That doesn't seem a good idea to me in a maintance kind of view.

Regards, Alex

 
0
 
LVL 13

Expert Comment

by:josgood
ID: 19682636
>>>>>>>> I suggest setting it to "Compile as C++ code"
>>>>That doesn't seem a good idea to me in a maintance kind of view.
Agreed, but lets get it working first and then make the investment in more fundamental changes.

>>>> rename all your *.c source to *.cpp
Agreed, but lets get it working first and then make the investment in more fundamental changes.

One thing at a time.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 19682889
>>>>> but lets get it working first and then make the investment in more ...

My experience shows that such kind of 'workarounds' have a very *tough* life. Sentences like 'never change a running system' or 'one thing at a time' prevent from doing the right rather than help.

If C++ code is in a .c file it should be corrected at once and not later (and actually it is not a big effort). Or, if the function was used both by C and C++ programs, the extern "C" is the only solution and of course it should be .c files. That is independent whether the linking errors were solved or not by doing so.

Regards, Alex
0
 
LVL 13

Expert Comment

by:josgood
ID: 19684940
Alex, I have a lot of respect for you.

Can we agree to disagree?
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 19685305
>>>> Can we agree to disagree?
Yes. (though I was serious and not picking on words only. I've seen too many statements in sources with a 'todo' or 'workaround' comment which simply was bad code and ever was).

>>>> Alex, I have a lot of respect for you.
Thanks, I hope my comment was not interpreted as not being respectful to you cause that never was the intention. I have a lot respect for you as well even or cause we have different backgrounds.

Regards, Alex
0
 
LVL 13

Expert Comment

by:josgood
ID: 19685408
Alex, thank you and we're cool.  I never felt any disrespect.

And I agree there are _way_ too many todo statements in code, and too much bad code, and too much bad design, for that matter.  Keep on fighting the good fight!
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 19685694
TODO: beer x 2
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 19695891
My C++ files are actually generated and I created the python program that generates them, so, noticing that the project I'm including them into is mostly C despite being compiled with /TP, I changed the python program to generate C files. They now also have .c and .h extensions.

However the LNK error persists, and I have it for any functions I try to call from these new files (despite the fact they are definitely found and compiled by the compiler and they work just great in an empty new project.

I'm beginning to wonder if the problem is not related to the complexity of the solution. It has 44 projects, despite the fact that it finds and compiles the files, perhaps the linker is getting confused. Only the 1 project of the 44 that I use this code in has the additional include directory containing my code in it's config. This project is a subproject that produces a lib used by some of the others.

Any Ideas? Now I'm really baffled...

Thanks,
-Sandra
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 19695898
Sorry that reads wrong, I only use my code in 1 project, that makes 43 other projects, some that build on that one which do not use my code or have any changes added by me.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 19696082
Are you building using a Makefile or working your Python-generated modules into a Visual Studio project? It sounds like your Makefile or project doesn't have backup.obj in it.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 19696109
Check that backup.obj is generated. Then try doing a command-line link.

e.g. Run vcvars32.bat and then:

   cl.exe <all the other .obj files> backup.obj innobase.lib <all the other .lib files>

If this works you can then apply the appropriate changes to the project / Makefile.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 19696198
>>>> Any Ideas? Now I'm really baffled...
Did you try renaming the c files to cpp? It really doesn't matter whether the generator made a .c extension. C is a subset of C++, hence anything (ok, nearly anything) that compiles as .c would compile as .cpp either. The only difference is that as C++ code any function name was mangled with some suffixes regarding the argument types. That is cause C++ allows to use the same function name but with different arguments (what is forbidden in C).  That isn't an issue for the compiler but the linker would look for the mangled names when called in a C++ source. But the object has unmangled names if compiled as C source.

Note, in Visual Studio you would need to remove the .c files from project tree and add the renamed .cpp files.

Regards, Alex
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 19696247
rstaveley:

I checked and there is a backup.obj file created in the same dir as the other .obj files.

itsmeandnobodyelse:

Good point. I've tried both .cpp and .c files with the same result though (at different intervals, it may still be possible that you're on to something there.)

However you guys seem to be bang on with the name mangling business. Looking at backup.obj in a hex editor I find right at the end:

backup_block@@YAHHHHPAU_object@@@Z

which looks to me like C++ name mangling, which shouldn't be applied to a .c file! Certainly there is no _backup_block in the obj file which means the linker is correct about it not being there. So how do I get the compiler to build a C obj file for it instead of C++? I don't want to change the /TP setting. Add extern "C" to the header and c file?

Thanks,
-Sandra
0
 
LVL 17

Accepted Solution

by:
rstaveley earned 500 total points
ID: 19697653
If you write your function thus, it will not mangle:

--------8<--------
#ifdef __cplusplus
extern "C"
#endif
int backup_block(int arg0, int arg1, int arg2, char* arg3) {

    // ...

}
--------8<--------

It would be good to get the extern "C" into the header too, but you probably don't want to edit the MySQL header files (assuming that's what innobase.lib is about?). Try changing the .cpp/.c module only. Your compiler will define the symbol __cplusplus (with a double underscore), if it is compiling in C++ mode. The header will be misinforming all other C++ modules which you compile that your function is mangled, but assuming the only code that calls backup_block is in innobase.lib, you will be OK, because that expects it not to be mangled.
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 500 total points
ID: 19697773
>>>> It would be good to get the extern "C" into the header too
You can have the same by putting the extern "C" around the include statements of those headers:

#ifdef __cplusplus
extern "C"
{
#endif

#include "generated_c_header1.h"
#include "generated_c_header2.h"
...

#ifdef __cplusplus
}
#endif

If the source you do that is a .cpp you may omit the #ifdef __cplusplus

extern "C"
{

#include "generated_c_header1.h"
#include "generated_c_header2.h"
....
}

Note, in any case you should switch off PCH  (precompiled header option) cause the preprocessor ignores include statements (and macros around) if there are includes of precompiled headers (like stdafx.h).

>>>> backup_block@@YAHHHHPAU_object@@@Z
>>>> looks to me like C++ name mangling, which shouldn't be applied to a .c file!
Yes, it is a mangled function name and the cause for the linker errors. I don't know why the backup.obj is compiled with C++. It can be that you included a C++ header or use PCH or link with a makefile which invokes the C++ compiler for all sources. If you build the project via VC build in Visual Studio you may check your .vcproj file by editing it in text mode. Look for the backup.c  source and check which compile options were invoked.

Anyhow, the extern "C" will prevent name mangling, hence it is the way to go.

Regards, Alex
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 19703647
Thanks guys! It's working now!

-Sandra
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
Article by: evilrix
Looking for a way to avoid searching through large data sets for data that doesn't exist? A Bloom Filter might be what you need. This data structure is a probabilistic filter that allows you to avoid unnecessary searches when you know the data defin…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
Suggested Courses

755 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question