问题
I'm trying to call static method from my TEST, but I'm getting unresolved external symbol. What I've done so far: Created 3 projects:
- GoogleTest project as a static library - compiled gtest-all.cc and gtest_main.cc
- MyProject - where I keep my .h and .cpp files
- UnitTest project - where I keep tests
I've set up UnitTest's additional directories, lib directories, and referenced GoogleTest and MyProject. Tests run fine until I call static method from one of my classes...
Linker options:
/OUT:"D:\SkyDrive\Projekti\Visual Studio 2010\Projects\File System\Debug\Unit Test.exe" /INCREMENTAL /NOLOGO "..\lib\part.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" "D:\SkyDrive\Projekti\Visual Studio 2010\Projects\File System\Debug\Google Test.lib" /MANIFEST /ManifestFile:"Debug\Unit Test.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"D:\SkyDrive\Projekti\Visual Studio 2010\Projects\File System\Debug\Unit Test.pdb" /SUBSYSTEM:CONSOLE /PGD:"D:\SkyDrive\Projekti\Visual Studio 2010\Projects\File System\Debug\Unit Test.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE
Error:
error LNK2019: unresolved external symbol "public: static char __cdecl FS::mount(class Partition *)" (?mount@FS@@SADPAVPartition@@@Z) referenced in function "private: virtual void __thiscall Cluster_KernelFS_mountPartition_Test::TestBody(void)" (?TestBody@Cluster_KernelFS_mountPartition_Test@@EAEXXZ) D:\SkyDrive\Projekti\Visual Studio 2010\Projects\File System\Unit Test\cluster.obj
回答1:
From our exchange of comments it looks clear that the linkage of your
googletest unit-test project (Unit Test
) does not include necessary object files generated by the project that it is supposed to test (MyProject
). fs.obj
and
kernelfs.obj
are at least two that are missing and from inspection of the
failing linker commandline it appears that you are linking none of the object files that
implement the classes or functions you want to test (if there are any more)
You seem to believe that adding a Visual Studio project reference to MyProject
to Unit Test
will automatically provide the missing object file dependencies to Unit Test
, but it won't.
The quickest way to remove the linkage errors would simply be to add the missing object files generated by MyProject
to the Unit Test
s project's Configuration Properties -> Linker -> Input -> Additional Dependencies.
You could add each of the missing .obj
files by a fully-qualified pathname that locates
it in the Debug
output directory of MyProject
. Or more easily, you could add the path to that Debug
directory to Configuration Properties -> Linker -> Input -> Additional Directories, and then simply add the unqualified name of the missing .obj
file to Additional Dependencies.
But this would be a flawed solution because of course you want Unit Test
always to
build on the latest source version of MyProject
and not just whatever MyProject
object
files happen to exist at the time. In that case you have two options:-
a) You can add the source files that generate the missing
.obj
files to theUnit Test
project as well asMyProject
. InUnit Test
's Solution Explorer view, right-click Source Files and navigate Add -> Existing Item. In this case you must take care that whenever your add a new source file toMyProject
you also add it toUnit Test
.b) This option assumes that both projects are in the same solution. If they're not you can make them so. Then you can, first, carry out the quick-but-flawed solution (and test it). Then to fix the flaw, you can make
Unit Test
dependent onMyProject
, so that whenever you buildUnit Test
,MyProject
will automatically be built first if it is out-of-date. To create this dependency, right-clickUnit Test
in the Solution Explorer pane, navigate Build Dependencies -> Project Dependencies -> Dependencies and tick the checkbox to makeUnit Test
depend onMyProject
. In this case you must take care that whenever a new.obj
file is to be generated byMyProject
you add it to the additional linker dependencies ofUnit Test
.
(b) Is the better practice.
All of the above assumes that you have correctly configured Unit Test
so that the compiler searches the include-directories of MyProject
and correctly locates its header files. You don't seem to have any build errors on that score.
Follow up Q. 1
Could you explain to me why doesn't the linker link any object files from MyProject (and I have to add them manually).
As far as the Visual Studio is concerned, MyProject
and Unit Test
are just two projects
contained in the same solution that build different executables. It doesn't "know" that the purpose of Unit Test
is to unit-test MyProject
and therefore will need to link all of the object files generated by MyProject
that contain functionality that Unit Test
is going to test. So why would it automatically add MyProject
's object files to Unit Test
's linkage?
Even if Visual Studio did somehow know that the purpose of Unit Test
was to unit-test MyProject
, how would it know which of MyProject
's object files it should link in Unit Test
? One of them might contain a main()
function - which will in fact be the case if MyProject
builds a console application - but Unit Test
also generates a main()
function in one of its object files; so linking all the MyProject
object files in Unit Test
would be impossible: it would cause a multiply defined symbol
error.
I pointed out that giving Unit Test
a project reference to My Project
does not have the effect of adding all My Project
's object files to Unit Test
's linkage. You now see one
reason why it couldn't have that effect.
And that reason exemplifies a more general one: When you link object files to build an executable, it's a linkage error for the same symbol to be visible in multiple object files. Which one is supposed to get linked? But of course it's not any kind of error for the same symbol to be visible in the linkages of different executables. That means you can't simply scoop up a bunch of object files from the linkage of one executable and add them to the linkage of another executable and expect it to work. If you want to add object files from one executable to the linkage of another, you have to know that some such mixture can be linked and what mixture you want. You have to know which symbols are meant to be linked from which object files to make the second executable and select the object files accordingly. As you say, it's a "manual" exercise.
Visual Studio's Project Reference feature would help you if MyProject
generated a library rather than an executable. In that case creating a reference from Unit Test
to MyProject
would (among other things) tell Visual Studio that by default the MyProject
library will be added to the linkage of Unit Test
. Libraries, unlike plain object files, are created for the purpose of being being linked with different executables, so it's natural for the MS Project Reference feature to support automation of library dependencies. It's also natural to assume that if a project generates an executable, not a library, then its object files are just a by-product and not intended to be linked with other executables.
The text-book way of organizing your work would be in three projects:-
MyLib
, generating library that contains all the functionality you want to unit-test.MyProject
, generating the same executable as at present, but linkingMyLib
Unit Test
, generating an executable that unit-testsMyLib
, also linkingMyLib
Follow up Q. 2
Explain to me how to configure the linker to link .objs from MyProject's debug folder?
I already have. Paragraph 4, "Or more easily..." etc. There is no way you can avoid having
to specify the individual .obj
files to be linked. You can't instruct the linker "Just link whatever object files you find in /path/to/MyProject/Debug
", because for the reasons I've explained, the linker doesn't do things as sloppy as that.
来源:https://stackoverflow.com/questions/23042424/googletest-testing-framework-c-static-method-linker-error