问题
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 Tests 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
.objfiles to theUnit Testproject 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 toMyProjectyou 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 Testdependent onMyProject, so that whenever you buildUnit Test,MyProjectwill automatically be built first if it is out-of-date. To create this dependency, right-clickUnit Testin the Solution Explorer pane, navigate Build Dependencies -> Project Dependencies -> Dependencies and tick the checkbox to makeUnit Testdepend onMyProject. In this case you must take care that whenever a new.objfile is to be generated byMyProjectyou 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 linkingMyLibUnit 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