Strange link error when #ifdef #else is defined - c++

I face a very strange link problem with VC 2010. Now I am developing a C++ library, and in order to make debug much easier, for some functions the library provides two function interfaces. For example,
class Object
{
public:
int fun(std::vector<int> &auxiliary_variable_for_debug_purpose);
int fun();
}
It is also possible to reorganize this class in this way:
class Object
{
public:
#ifdef DEBUG_INDICATOR
int fun(std::vector<int> &auxiliary_variable_for_debug_purpose);
#else
int fun();
#endif
}
By doing so I except to give a clear interface to the user.
The problem I face now is both int fun(std::vector<int> &auxiliary_variable_for_debug_purpose); and int fun(); will invoke another function called void help_function(), which is declared and defined in separated files.
file.h
void help_function()
and
file.cpp
void help_function()
{
// do something
}
As you can see void help_function() is the same regardless whether DEBUG_INDICATOR is defined or not. If I defined DEBUG_INDICATOR, I can compile the class with int fun() function without any problem. However, when I undefined DEBUG_INDICATOR, the error LNK2001 error happens, suggesting unresolved external symbol void help_function(). I have tried every possible means to figure it out, but failed. Any ideas will be appreciated.
EDIT
The library I have built is a dynamic library. Regardless whether DEBUG_INDICATOR is defined, the library can be built, and the link error only happens when the library is invoked.

Since you've not posted the exact error message you are getting, this MSDN link might help you.
Tip: Be specific while asking your question if you wish to receive accurate answers.

Related

C++ undefined reference to enum type at linking time

This is my first time encountering this type of linking error for 20 years while trying to use other people's code.
Here I will be brief and using abbreviated examples.
Say the file enums.hpp
==== content====
#ifndef _BLABLA_
#define _BLABLA_
enum SomeKind { BLACK, RED, GREEN }
static void parse(const std::string& s, SomeKind) {
// definition
}
..... More enum, and static functions
#endif
In this file there are several enum and parse. Because of the STATIC keyword, the compiler will complain about the unused functions. I experimented by moving the definition of those function to a enum.cpp file. Then at link time, I am getting the error message:
undefined reference to `someNameSpace::SomeKind
One solution I will try to use the library as is (I will probably do that). This project (I am using) is a CMake project. What's a better way of organizing the original code to git rid of both problems: unused function, and undefined reference?
After removing the static label then it get rid of the linking problem of the enum. Essentially the new organization is as:
enums.hpp
enum SomeKind { }
void someFunction(SomeKind sk);
enums.cpp
void someFunction(SomeKind sk) {
// definition here
}
I think elimination of the static make the function visible and some how included in the linking stage. This is a big library, I have only a few hours looking into this library.

MSVC 2017 creates copies of template function in shared libraries

While trying to replicate the behavior in this question in Visual Studio 2017 I found that instead of linking &FuncTemplate<C> to the exact same address the function template<> FuncTemplate<C>() {} gets copied into dllA and dllB so that the corresponding test program always returns not equal.
The solution was setup fresh with 3 Win32Projects, one as ConsoleApplication, the others as DLL. To link the DLLs I added them as reference to the console project (linking manually didn't work either). The only change in code I made was adding the __declspec(dllexport) to a() and b().
Is this behavior standard conforment? It seems like the ODR should be used here to collapse the copies of the function. Is there a way to get the same behavior seen in the other question?
Template.h
#pragma once
typedef void (*FuncPtr)();
template<typename T>
void FuncTemplate() {}
class C {};
a.cpp - dll project 1
#include "Template.h"
__declspec(dllexport) FuncPtr a() {
return &FuncTemplate<C>;
}
b.cpp - dll project 2
#include "Template.h"
__declspec(dllexport )FuncPtr b() {
return &FuncTemplate<C>;
}
main.cpp - console project
#include <iostream>
#include "i.h"
// seems like there is no __declspec(dllimport) needed here
FuncPtr a();
FuncPtr b();
int main() {
std::cout << (a() == b() ? "equal" : "not equal") << std::endl;
return 0;
}
C++ compilation is generally split into two parts, the compiler itself and the linker. It is the job of the linker to find and consolidate all the compilations of an identical function into a single unit and throw away the duplicates. At the end of a linking step, every function should either be part of the linker output or flagged as needing to be resolved at execution time from another DLL. Each DLL will contain a copy of the function if it is being used within that DLL or exported from it.
The process of resolving dynamic links at execution time is outside of the C++ tool chain, it happens at the level of the OS. It doesn't have the ability to consolidate duplicates like the linker does.
I think as far as ODR is concerned, each DLL is considered a separate executable.

Unresolved external symbol when putting definition in CPP file

For the life of me I cannot figure out what is causing this... I keep getting unresolved external symbol error. However, if I put an empty definition in the header file it compiles correctly.
WINMAIN.CPP
#include "FILE_XXX.H"
int WINMAIN WinMain(...)
{
EnableOpenTest(); // call like this
return 0;
}
FILE_WORKS_CORRECTLY.H
#ifndef _FILE_WORKS_CORRECTLY_
#define _FILE_WORKS_CORRECTLY_
void EnableOpenTest() { }
#endif
However, when I do something like this (correctly), it does not work and I get a compile-time error.
FILE_DOES_NOT_WORK_CORRECTLY.H
#ifndef _FILE_DOES_NOT_WORK_CORRECTLY_
#define _FILE_DOES_NOT_WORK_CORRECTLY_
void EnableOpenTest();
#endif
FILE_DOES_NOT_WORK_CORRECTLY.CPP
#include "FILE_DOES_NOT_WORK_CORRECTLY.H"
void EnableOpenTest() { /* do work here */ }
UPDATE:
Upon further investigation, I found the issue has to do with me having multiple projects in the same solution. I then try to reference a function in one project from another project. Obviously I'm doing this incorrectly.
The only mistake i see is that in the cpp file you need to include the return type as well. It should be
void EnableOpenTest()
{
//Enter Code Here
}
Inside of FILE_DOES_NOT_WORK_CORRECTLY.CPP:
EnableOpenTest(){ /* do work here */ }
must be
void EnableOpenTest(){ /* do work here */ }
Looks like your compiler sets the missing return type to int instead of yelling at you with a error message.
You should turn on compiler warnings, it would allow you to notice such errors very quickly.
Also, inside of FILE_WORKS_CORRECTLY.H you have another error:
void EnableOpenTest() { }
must be
inline void EnableOpenTest() { }
Otherwise it will trigger a error message if this header is included twice (i.e. in more that one .cpp file).
Solved it!
Additional projects needed to be static library (main project .exe)
Added References of library projects to main project
Obviously the file structure caused a lot of these issues.

Unresolved External Symbol C++

I have read this informative stackoverflow question regarding unresolved external symbols, but I am still not sure how to solve my issue.
Within Visual Studio 2012, I have a solution consisting of multiple projects, one of which is a static library called common. Each project that produces an executable consists of a header and associated cpp file of all global functions used throughout that specific program, called programglobals. In the process of developing one of these projects, I started duplicating some of this code from one project's programglobals to another. Now that I have completed all the projects, I want to extract the duplicate code into a associated header and cpp file within the common library, but I believe I might be referencing them incorrectly, which is producing these unresolved external symbol errors
Here is a dumbed down example of what I am currently attempting.
Common Library Files
//solutionglobals.h
void commonFunction();
//solutionglobals.cpp
void commonFunction() {
int asdf;
}
Project A Files
// programglobals.h
#include "../common/solutionglobals.h
void functionUsedInProjectA();
// programglobals.cpp
void functionUsedInProjectA() {
int x;
}
// output.h
#include "programglobals.h"
void asdfA();
// output.cpp
void asdfA() {
int x;
functionUsedInProjectA();
commonFunction();
}
Project B Files
// programglobals.h
#include "../common/solutionglobals.h
void functionUsedInProjectB();
// programglobals.cpp
void functionUsedInProjectB() {
int x;
}
// output.h
#include "programglobals.h"
void asdfB();
// output.cpp
void asdfB() {
int x;
functionUsedInProjectB();
commonFunction();
}
Any reference to commonFunction() results in an unresolved external symbol error.
Thanks!
You will have to specify in your executable projects that they reference the static lib. May be http://msdn.microsoft.com/en-us/library/vstudio/ms235627%28v=vs.110%29.aspx#uselibinapp helps (lower third of the article).
Before you can use the math routines in the static library, you must
reference it. To do this, open the shortcut menu for the MyExecRefsLib
project in Solution Explorer, and then choose References. In the
MyExecRefsLib Property Pages dialog box, expand the Common Properties
node, select Framework and References, and then choose the Add New
Reference button.
The linker cannot 'see' your function and as such thinks that it does not have an external symbol referencing it, hence the error.
You must #pragma comment(lib, [library here]) to reference the external function.
The following code can be used to reproduce this error:
[header file- test.h]:
#include "StdAfx.h"
void someOtherFunction();
void someFunction(string thisVar);
[code file- test.cpp]:
#include "StdAfx.h"
#include "test.h"
void someOtherFunction()
{
printf("Hello World!");
}
[function body for someFunction(string thisVar) is missing!]

Annoying DLL Issue (Unresolved External Symbol)

I am trying to build a dll to go along with my program in c++. The dll will be a basic library with a bunch of inheritable classes and general utilities, which can then be used dynamically by multiple other applications that will accompany the final product(A Game). I threw something together, only to find that I am recieving I maddening error. It is the famous "error LNK2019: unresolved external symbol". First off, I already found the solution to this, and here is the link: Unresolved External Symbol- Error in guide?
The chosen answer works. If I put my class into only a header file, it compiles perfectly fine, runs, and is all nice and pretty. However, I want to keep the declaration and implementation separate, and if I try to move the implementation to a separate cpp I receive the LNK2019 error. This is due to some kind of inlining, I just want to know how I can bloody fix it before I start tearing my hair out.
Can anyone help me with this? Here is my class:
Header:
#ifndef MYDLLTESTCLASS_H
#define MYDLLTESTCLASS_H
class __declspec( dllexport ) MyDLLTestClass {
public:
MyDLLTestClass();
void setX( int x );
int getX();
private:
int x;
};
#endif // MYDLLTESTCLASS_H
CPP:
#include "MyDLLTestClass.h"
MyDLLTestClass::MyDLLTestClass() {
}
void MyDLLTestClass::setX( int x ) {
this->x = x;
}
int MyDLLTestClass::getX() {
return x;
}
Separate like above, the code wont compile. But if I throw the declaration and implementation together It works, so if I do this:
#ifndef MYDLLTESTCLASS_H
#define MYDLLTESTCLASS_H
class __declspec( dllexport ) MyDLLTestClass {
public:
MyDLLTestClass();
void setX( int x );
int getX();
private:
int x;
};
MyDLLTestClass::MyDLLTestClass() {
}
void MyDLLTestClass::setX( int x ) {
this->x = x;
}
int MyDLLTestClass::getX() {
return x;
}
#endif // MYDLLTESTCLASS_H
It will work. Again, I WANT the declaration and implementation separate.
Here is the build report when I use separate declaration and implementation.
http://pastebin.com/HMEpeEgn
This was actually far easier to solve than I realized; it turns out the it was a visual studio setting all along. First, you need to add the dll project to your current project(Which will be using it). Then you need to right click on you current project and Follow these two pictures:
And then add your dll, which might just need to be check-marked(Mine was simply missing the checkmark).
After that your project will compile perfectly fine! No need for nasty-ass #ifndef macros like every webpage has attempted to portray(which also didn't work mind you)