• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 898
  • Last Modified:

LNK2019: unresolved external symbol

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
Sandra-24
Asked:
Sandra-24
  • 6
  • 6
  • 5
  • +3
2 Solutions
 
josgoodCommented:
Could this be a name decoration issue?

I notice the unresolved symbol has a leading underscore.


0
 
Sandra-24Author Commented:
Could be, why does it have that? Neither backup_block or fil_write have leading underscores so the compiler must be adding them.
0
 
josgoodCommented:
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
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
jkrCommented:
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
 
Sandra-24Author Commented:
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
 
josgoodCommented:
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
 
draguljCommented:
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
 
draguljCommented:
Just one important thing more: extern "C" should be used in a function definition, not declaration.
0
 
rstaveleyCommented:
I agree with dugulj.

Write your functions as:

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

    // ...

}

0
 
itsmeandnobodyelseCommented:
>>>> 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
 
josgoodCommented:
>>>>>>>> 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
 
itsmeandnobodyelseCommented:
>>>>> 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
 
josgoodCommented:
Alex, I have a lot of respect for you.

Can we agree to disagree?
0
 
itsmeandnobodyelseCommented:
>>>> 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
 
josgoodCommented:
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
 
rstaveleyCommented:
TODO: beer x 2
0
 
Sandra-24Author Commented:
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
 
Sandra-24Author Commented:
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
 
rstaveleyCommented:
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
 
rstaveleyCommented:
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
 
itsmeandnobodyelseCommented:
>>>> 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
 
Sandra-24Author Commented:
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
 
rstaveleyCommented:
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
 
itsmeandnobodyelseCommented:
>>>> 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
 
Sandra-24Author Commented:
Thanks guys! It's working now!

-Sandra
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 6
  • 6
  • 5
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now