There are two problems I run into occasionally. One is compile time assertions and the other is a header file being included in multiple places in weird ways (this is not my code so I cannot fix it by not including it in weird ways. Even if I tried, it would take too many hours/days as it is deeply embedded), e.g.:
class Foo
{
public:
#include "VariableDeclarations.h" // Some file that has all the variables that need to be declared
// which is also included by several other classes in the same way
};
The above code is a simplication of what I am currently dealing with. Of course, the class Foo is doing other things as well.
Now if I add another variable declaration to the header in this case, and the file Class Foo is in does not know about the type, I will get a compile error. To fix it, I include the necessary headers. Problem is, all the compiler tells me is "undeclared identifier" and the file name comes up as VariableDeclarations.h. I would like to know which file included the declarations and consequently did not know about the type that I just added.
Similar thing happens with compile time assertions. I have no indication as to which line/file caused the error. It just gives me the error (e.g. in Eigen math library, I was experiencing this a lot).
In g++, you can use the verbose option, -v. For intel, the same flag -v should work. For MSVC there is a project option you can tweak somewhere in one of the build settings: How can I make Visual Studio's build be very verbose?
The preprocessor pound sign (#) has to be the first symbol on the line for it to be processed, and the trailing ; shouldn't be there either:
class Foo
{
public:
# include "VariableDeclarations.h"; // Some file that has all the variables that need to be declared
// which is also included by several other classes in the same way
};
Also, both GCC and MSVC have a switch to only run the preprocessor and show you the generated file. That's an excellent tool to debug this kind of stuff.
Related
I have a header which in certain files needs to be ahead of any other headers. But cpplint complains as follows:
Found C system header after other header. Should be: V
iew.h, c system, c++ system, other. [build/include_order] [4]
and in certain cases:
Found C++ system header after other header. Should be
: TorqRootViewWin10.h, c system, c++ system, other. [build/include_order] [4]
I thought maybe // NOLINT could work, but it looks like it only works on errors in the specific line in which it is added, in this case the errors are in the following lines and not on the line of the header i included ahead of others. The other option I have is to use // NOLINT in all the other lines following my header. But that feels dirty. Is there any other way of doing this?
No, the NOLINT syntax is quite limited, also see google#31.
The error category can be removed in the command line options to never check include order, if your project does not want to follow the order required by cpplint.
I cannot tell from your error description whether you believe cpplint is wrong or inconsistent about it's warning, or whether you just wish to order your headers in a different way than cpplint.
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 9 years ago.
I'm trying to wrap my head around C++ developement using the SFML library. I'm following a tutorial (http://www.gamefromscratch.com/page/Game-From-Scratch-CPP-Edition-Part-7.aspx), and using visual studio 2010.
A problem I keep running into regards unresolved externals. I'm really struggling with this, because unlike most errors I run into, it doesn't seem to a) have anything to do with the code, and b) doesn't behave consistently. Rather than give y'all a specific example and ask for help solving that one example, I'm hoping to develop a more reliable way of attacking these problems. I'll give you an outline of a common occurance though.
I have a solution with 8 header files and 8 cpp files that correspond to them. The solution is stable: It compiles and runs with no errors or warnings.
I'll go into a header file and add this line:
virtual void DoNothing();
I'll then go into the matching cpp file and write the method:
void DoNothing(){};
I compile and run, and get 5 unresolved external errors. They don't point to any line of code, so I don't really know how to fix them, but I obviously did something wrong. Fair enough. Trying to get back to a stable state, I delete the two lines of code I had inserted, and compile. Even though the code is identical to the last stable state, I get the same unresolved external errors.
Trying random things, I go into another cpp file and reverse the order of two included header files. The game compiles now. If I switch the order of the included header files back, it compiles.
What the hell are unresolved external errors? Why don't they seem to behave consistently with the code I've entered? How do I read them to find out what the problem is, and how do I avoid them in the first place?
Thank you.
ps: If there are more specific details I should provide, please just let me know.
"Unresolved External" errors mean that your code is referring to something (usually a function or method, but can be a variable too) that does not exist. These are link errors, and not compile errors; that's why you don't get a line number and more helpful error messages.
Let me give you a little background on how C++ code is turned into an executable (and keep in mind that I'm simplifying things a bit.)
Each C++ source file (and not header file) in your project is compiled separately. A ".cpp" file and all the headers it includes are compiled into what is called an object file or object code. (These files have a ".obj" or ".o" extension.) You can also think of library files (that is ".lib" files on Windows and ".a" files on Linux) as a collection of these object files, stored for later use.
To produce the executable programs (e.g. the EXE or DLL file on Windows) all these object files are linked together are voila!
Now, the important thing here is that each source file is compiled in isolation and independent from other source files. So, if the code in one file calls a function that is implemented in another file, the compiler won't see the actual body of that function and can only assume that as long as the declaration of the called function is visible (i.e. the prototype, i.e. the line you write in headers,) then these files are going to be linked together eventually and will leave the task of actually making the call to the linker. This usually means that as long as you include the right headers, your compiler is going to be happy.
But the linker is going to be more tenacious and pedantic. At link time, you really really need to provide the body (i.e. the implementation) of all the functions that you use all over the project. It is your task to make sure that all the right object files and libraries are linked together and the implementation of each used function exists somewhere among them exactly once (no more, no less.)
This brings us to your problem. When you get an "unresolved external" linker error, this means that the body of a function you've called does not exist anywhere in object files and libraries that you are linking together.
Obviously, one of two things is happening. Either you have included the header for an external library, but have forgotten to link in the library file itself (which is not your problem here) or you've declared (i.e. written the prototype for) a function but have forgotten to implement its body.
Keep in mind that the linker is really strict here. If you declare something like this in your class:
class Foo {
void bar (int x);
};
and then in your ".cpp" file, implement this function:
void bar (int x)
{
// Do nothing
}
then you'll get an unresolved external error if you actually call Foo::bar() anywhere in your program, because the implemented bar() is not a method of Foo (you should have implemented void Foo::bar (int x) {}.) Similar things happen if you slightly misspell or get the type of the arguments wrong or whatnot.
Reading linker errors and making sense from them can be hard. Sometimes, the name that the linker is complaining about (the "symbol" it says it can't find) is all mangled beyond recognition. This has to do with *Application Binary Interface*s (ABI) and several decades of history and precedence. Anyways, most of the time, if you look closely and the link error message, you can see what the function name was and check your code (or libraries) and try again.
Also, though it's rare, it sometimes happens that in order to solve some link issues, you have to resort to completely rebuilding your project.
Every time I've seen behavior like this it has been because of a circular reference between projects. For example, project A has a reference to an object/symbol implemented in project B while at the same time project B has a reference to an object/symbol from project A. Every time you build your solution, the tools have to compile one project first, then the other. If you make a change to the second project to be compiled, the first one cannot see the change on the first round of compilations and the build fails. If you manage to manually build project B (against a now obsolete copy of library B), then the solution starts to build correctly. More complex cycles are possible (e.g. A depends on B, which depends on C, which depends on A). You don't mention multiple projects explicitly, but I bet you have them.
These circular references are common on large solutions that have been around for a long time and have grown slowly over time. People get in habit of adding links from everything to everything because they need one function from here, a struct from there...
Hunt down these dependencies. You should be able to do a full clean rebuild from nothing but the source code. Your dependency tree should look like... Well, a tree; not a graph.
I am using VIM for C++ development for quite some years now and I don't want to debate the question whether to use an IDE or powerful text editor for software development. Up to now I've been involved mostly with a header-only template library where everything is either a template or declared inline, thus .cpp files don't play a major role.
Recently I'm more involved in "traditional" C++ development, facing the old issue of header / non-header file synchronization. I'm wondering if there are any command-line tools around that could be used in a make target or be integrated into VIM to handle this job, i.e. update header files based on .cpp files. Basically, declarations of classes / structs or (template and inline) implementations should be ignore int he header files, while function declarations should be added, removed or updated based on the .cpp file.
I'm aware of the lzz tool, however, that requires you to actually code in an additional, third file format that is then preprocessed to .h / .cpp files before the actual compilation.
Is there anything around that can do the job? How do other non-IDE developers handle this problem?
As I myself am very curious about answers to your first question unfortunately I am not able to give you any good advice here.
To at least give you an answer to your second question: This is the somewhat semi-automatic way I use to manually add missing or adjust changed declarations in out of sync header files.
use the compiler with warnings enabled (!) to spot missing / changed declarations:
Adjust declarations
After changing the signature of a function definition gcc will throw an error like the following one:
error: conflicting types for ‘....’
note: previous declaration of ‘....’ was here
Fixing this one is relatively easy as both a reference to the definition and the corresponding declaration are already given in the error message.
As I am an emacs user I can't tell you the way this is done in vi, but I am quite sure there is an equally simple way to automatically jump to this spots.
All that has to be done is:
jump to location one copy the line
jump to location two replace old line with the copy and add a trailing ;
Missing declarations
If on the other a new function was added without adding it's prototype to the corresponding header file gcc will throw something like:
warning: implicit declaration of function ...
Fixing this one a tag table comes in handy. Again I don't know for sure how this is handled in vi, but I am quite sure there is some way to quickly jump to the function definition given by its name in the compiler warning as well.
Workflow here looks like this:
jump to function ....'s definition, copy line
switch to header file, paste line and add a trailing ;
While this method is anything but elegant it has turned out to be working for those cases in which I forgot to adjust the header to keep it in sync with the source file, which can be done with a few keystrokes.
A broken Example
To demonstrate its application by example here a minmal program that needs it's headers to be fixed:
/* main.c */
#include "add.h"
int main (int argc, char *argv[]) {
int a=0, b=0;
add (a, b);
sub (a, b);
return 0;
}
Both functions add and sub are defined in add.c shown below:
/* add.c */
#include "add.h"
int add (int a, int b) {
return a + b;
}
int sub (int a, int b) {
return a - b;
}
The culprit add.h shows both a signature mismatch of the function add and a missing declaration of the function sub:
/* add.h */
long add (long a, long b);
Trying to compile will result in:
gcc -Wall main.c add.c
main.c: In function ‘main’:
main.c:7: warning: implicit declaration of function ‘sub’
add.c:3: error: conflicting types for ‘add’
add.h:2: note: previous declaration of ‘add’ was here
Fixing the example
Missing declarations
The first problem:
main.c:7: warning: implicit declaration of function ‘sub’
Is due to the fact that a declaration of sub is missing in add.h
Finding the right signature:
C-x` (next-error) will jump to the location of the error
M-. (gtags-find-tag) will prompt for the tag to lookup
RET will jump to the definition of sub as the symbol at point is the default
M-z{ (zap-to-char) C-y (yank) to copy the signature
Up to here all steps could have also be done automatically by a keyboard macro as no intervention was needed. The next part will have to be done by hand:
open the "correct" header file
and navigate to the spot where the declaration should be entered
As the choice of "correct" header file and "correct" location most probably is a matter of taste in contrast to the steps taken so far I don't think there's much automation possible here.
Finally the last step is to paste the copied signature:
C-yM-y paste the copied signature
DEL; to replace { with ;
Adjusting declarations
Next the mismatch between adds declaration and definition has to be fixed.
add.c:3: error: conflicting types for ‘add’
add.h:2: note: previous declaration of ‘add’ was here
To copy the new signature from the definition:
C-x` (next-error) will jump to the location of the definition
M-z{ (zap-to-char) C-y (yank) to copy the signature
To replace the declaration:
C-x` (next-error) will jump to the location of the declaration
M-z; (zap-to-char) to delete the old declaration
C-yM-y now paste the copied signature
DEL; to replace { with ;
And back again
Since two buffers have been poped:
M-2M-x burry-buffer should go back to buffer that was visited before
Summary
As you can see while not a too time consuming process constantly jumping back and forth to fix missing or wrong declarations using this approach is still a rather tedious task I only use it to fix up declarations that I mistyped or completely missed in the first run.
Manually placing the "correct" declarations into the header still is the main approach that I take.
As laying out the API prior to implementing it might not be the worst idea IMHO this strategy shouldn't be a choice too bad.
There is a program called makeheaders from the fossil project (vcs alternative to git).
You can easily compile it from source code.
I also suggest that you read the doc.
Note that it does not work well when your headers and source file are not in the same directory as you can't specify an output directory for the generated header files.
I have forked it to implement to allow specifying an output directory with an overly specific workflow but it is such a hacky job that I even hesitate to redirect you towards it. Use at you own risk : https://github.com/cassepipe/makeheaders
On UNIX-type systems, typically IDEs don't handle this job (in my experience). The build tool (which is not usually bundled with IDEs such as Eclipse, Emacs, etc.) will do this work.
In modern systems the best way to handle this is to let the compiler do it: after all, the compiler knows best. GCC, and most other UNIX/POSIX compilers, have options that will emit make-style dependency declarations during the compilation of a source file. You simply arrange for this in your makefile, then include the output files in your makefile, and it all works very well.
See, for example: http://make.mad-scientist.net/autodep.html
Then check out the GCC options such as -MMD -MP (these are preprocessor options).
I've copied and pasted some files from my windows machine to my linux one and ran into a few understandable problems with the conio.h and Windows.h headers, but I can't remember what they're needed for.
They're only in the main function so I commented them out and ran the program again thinking the errors would show me where they're needed so I could then google what headers would work similarly for linux.
The problem I have is that all the errors I get are in header files I've included in the main function, but don't have the Windows.h or conio.h headers included.
The question I have is how/why: -
Does the compiler look at each header file in turn, get to the windows.h header and stop then when that's commented out it get's to my "Chapter_7.h" header and find all the problems in there.
Or could the commenting out of the headers in the main.cpp somehow affect the headers I wrote.
Or (possibly more likely) Is there another option I've overlooked?
Thanks for any answers.
It is due to the way .h files are "INCLUDED" in the .cpp. During compilation, all the text in the header files is copy pasted into the including .cpp file. This means later .h files will have access to earlier ones.
This looks to be what is happening in your case, windows.h would have been the first include, and subsequent headers have been using it all along.
//#include <window.h>
//#include <conio.h>
#include "myheader.h" // can no longer use windows.h or conio.h
#include "myheader2.h"
You can say header contents are copy-pasted inside the file they're included in, if that's what you mean.
Or could the commenting out of the headers in the main.cpp somehow affect the headers I wrote.
Definitely. Assume:
//header1.h
#define X 1
//header2.h
#ifdef X
int a = 0;
#else
int a = 1;
#endif
a will be defined differently if header1.h is included before or after header2.h.
The first step of fixing "I'm using headerfiles that I can't use on this machine" is to remove those files, compile the code and see where things break - it's nearly always making compiler errors, so you should be able to find it quite easily.
conio.h allows console io, and it may require a bit of work to fix that into Linux. Depends on exactly what you are using.
windows.h is much more complex to explain, as it essentially gives you all of the Windows API functions, and a huge number of type declaration, and there are many of those. Most of which your program probably never uses [directly].
One of the common problems with "using a headerfile that doesn't exist somewhere else" is that you end up using some types that are declared in the headerfile. So for example, windows.h will declare LONG, HANDLE, and a vast number of other types. These types are then used in structures and function declarations elsewhere, and when you remove windows.h it will cause all manner of follow-on problems.
My approach is always to fix the first problem first, then compile again. The reason for this is that the compiler often gets "confused" if something strange appears. It's a bit like if you were to tell a friend how to drive to your house, and you say "When you see the big-oaktree on the left, you take the next right". Unknown to you, the oak-tree has been cut down because it was dieing, and is no longer there. So your friend drives where the oak-tree used to be, and turns right after another oak-tree later on along the road. Of course, now all OTHER instructions are completely uselss, because your friend is miles away from the correct road, and is never going to find your house without new instructions. The same thing happens when the compiler finds "surprising" or "missing" bits in the source-file. So fixing the first error, then compiling, fixing, compiling, usually gets you to a point where your code compiles. Sometimes this involves writing new functions like this:
int GetTimeOfDay(void)
{
printf("%s:%d:%s: doesn't work yet, exiting...", __FILE__, __LINE__, __func__);
exit(1);
return 0; // to keep compiler happy.
}
Once you got all the code compiling, you start working out how to implement/replace those functions that you added to make it compile.
I'm currently getting compiler warnings that resemble the warning I gave in the question title. Warnings such as....
warning: 'boost::system::generic_category' defined but not used
warning: 'boost::system::posix_category' defined but not used
warning: 'boost::system::errno_ecat' defined but not used
warning: 'boost::system::native_ecat' defined but not used
As far as I know the program isn't being affected in any way. However, I don't like warnings hanging around, but I have no idea what these warnings are trying to tell me besides that something defined and related to boost is hanging around somewhere not being used. However, everything that I've defined, I've used. The boost libraries I'm using are the random library and the filesystem library.
When I check the source of the warning it brings up Boost's error_category.hpp file and highlights some static consts that are commented as either "predefined error categories" or "deprecated synonyms". Maybe the problem has something to do with my error handling (or lack of) when using the library?
Can anyone give some insight regarding why these warnings are popping up? Am I completely missing something?
P.S. Warnings are at max level.
I agree with #Charles Salvia, but wanted to add that at least as of Boost 1.44.0, these definitions are now wrapped -- to be excluded as deprecated. So if you aren't using them, just include the following lines before you include the header file:
#ifndef BOOST_SYSTEM_NO_DEPRECATED
#define BOOST_SYSTEM_NO_DEPRECATED 1
#endif
This relates to the error_code library in the Boost.System library. Boost error_codes contain two attributes: values and categories. In order to make error_codes extensible so that library users can design their own error categories, the boost designers needed some way to represent a unique error code category. A simple ID number wouldn't suffice, because this could result in two projects using conflicting ID numbers for custom error categories.
So basically, what they did was to use memory addresses, in the form of static objects that inherit from the base class error_category. These variables don't actually do anything except to serve as unique identifiers of a certain error category. Because they are essentially static dummy objects with unique addresses in memory, you can easily create your own custom error categories which won't interfere with other error category "IDs." See here for more information.
I suppose that what you're seeing is a side-effect of this design decision. Since these variables are never actually used in your program, the compiler is generating warnings. Suffice it to say, I don't think you're doing anything wrong.
I tried the BOOST_SYSTEM_NO_DEPRECATED suggested by #M.Tibbits, and it seemed to remove some instances of the warnings (in a big system built under linux), but not all.
However, using -isystem instead of -I to include the boost headers (and ignore their problems) did work for me.
Suggested by https://exceptionshub.com/how-do-you-disable-the-unused-variable-warnings-coming-out-of-gcc.html
Explained (obliquely) by GNU GCC: http://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html