Prev: Using signal in a runtime loaded DLL
Next: "PORTING C" > How to assign a value to a define statement?
From: John N. on 3 Feb 2010 10:23 I have stumbled across a problem involving linking to a static library that I was hoping someone could help me with. I want to create a static library which contains various methods that I will use from other code. In my simple example case, I try to call one of the two library methods from main(). Everything compiles correctly. However, when linking, I get the link error shown below. The source files (Methods.h, Methods.cpp, Tester.cpp) for my simple example are typed out at the end of this post. Methods.h and Methods.cpp are used to build a static library named support library.lib, while Tester.cpp is the main() which uses one of the two methods (method1) defined in Methods.cpp. The other method in the static library (method2) in Methods.cpp is not referenced by main(). It in turn references a method (methodDoesNotExist) that is declared in Methods.h, but is not defined in Methods.cpp. Thus, the static library compiles and is built with no errors, yet when I go to link it with the main() I get the link error shown below. Why does the linker give me this link error since I am not trying to use method2? One way to fix the problem would be to create separate .cpp/h files for each of the methods and then use all those files to create the static library. Is there any way to keep all the methods in the same file (for ease of maintenance), yet have the linker only resolve references that are used? Thank you. John N. Small example source files begin here: // Methods.h //************************************************* #include <string> #include <istream> const std::string method1( std::istream& stream_ ); const std::string method2( std::istream& stream_ ); const std::string methodDoesNotExist(); //************************************************* // Methods.cpp //********************************** #include <string> // std::string #include <istream> // std::istream #include "Methods.h" // ::Methods_xxx const std::string method1( std::istream& stream_ ) { return "from method1"; } const std::string method2( std::istream& stream_ ) { return methodDoesNotExist(); } //********************************** // Tester.cpp //**************************************************** #include "Methods.h" #include <fstream> #include <iostream> // std::cout #include <string> int main(){ std::ifstream stream; stream.open("testerParse.txt"); std::cout << ::method1( stream ) << std::endl; stream.close(); char c; std::cin >> c; } //**************************************************** Link Error: ------ Build started: Project: support library, Configuration: Debug Win32 ------ Compiling... Methods.cpp Creating library... Build log was saved at "file://c:\Test\BuildLog.htm" support library - 0 error(s), 0 warning(s) ------ Build started: Project: testerParse, Configuration: Debug Win32 ------ Linking... support library.lib(Methods.obj) : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const __cdecl methodDoesNotExist(void)" (?methodDoesNotExist@@YA?BV?$basic_string(a)DU? $char_traits@D(a)std@@V?$allocator@D@2@@std@@XZ) referenced in function "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const __cdecl method2(class std::basic_istream<char,struct std::char_traits<char> > &)" (? method2@@YA?BV?$basic_string(a)DU?$char_traits@D(a)std@@V? $allocator@D@2@@std@@AAV?$basic_istream(a)DU?$char_traits@D(a)std@@@2@@Z) C:\Test\testerParse.exe : fatal error LNK1120: 1 unresolved externals Build log was saved at "file://c:\Test\BuildLog.htm" testerParse - 2 error(s), 0 warning(s) ========== Build: 1 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
From: David Wilkinson on 3 Feb 2010 10:54 John N. wrote: > I have stumbled across a problem involving linking to a static library > that I was hoping someone could help me with. > > I want to create a static library which contains various methods that > I will use from other code. In my simple example case, I try to call > one of the two library methods from main(). Everything compiles > correctly. However, when linking, I get the link error shown below. > > The source files (Methods.h, Methods.cpp, Tester.cpp) for my simple > example are typed out at the end of this post. > > �Methods.h� and �Methods.cpp� are used to build a static library named > �support library.lib�, while �Tester.cpp� is the main() which uses one > of the two methods (method1) defined in �Methods.cpp�. > > The other method in the static library (method2) in �Methods.cpp� is > not referenced by main(). It in turn references a method > (methodDoesNotExist) that is declared in �Methods.h�, but is not > defined in �Methods.cpp�. Thus, the static library compiles and is > built with no errors, yet when I go to link it with the main() I get > the link error shown below. > > Why does the linker give me this link error since I am not trying to > use method2? > > One way to �fix� the problem would be to create separate .cpp/h files > for each of the methods and then use all those files to create the > static library. > > Is there any way to keep all the methods in the same file (for ease of > maintenance), yet have the linker only resolve references that are > used? > > Thank you. > John N. > > Small example source files begin here: > > // Methods.h > //************************************************* > #include <string> > #include <istream> > > const std::string method1( std::istream& stream_ ); > const std::string method2( std::istream& stream_ ); > const std::string methodDoesNotExist(); > //************************************************* > > // Methods.cpp > //********************************** > #include <string> // std::string > #include <istream> // std::istream > #include "Methods.h" // ::Methods_xxx > > const std::string > method1( std::istream& stream_ ) > { > return "from method1"; > } > > const std::string > method2( std::istream& stream_ ) > { > return methodDoesNotExist(); > } > //********************************** > > // Tester.cpp > //**************************************************** > #include "Methods.h" > #include <fstream> > #include <iostream> // std::cout > #include <string> > > int main(){ > std::ifstream stream; > stream.open("testerParse.txt"); > > std::cout << ::method1( stream ) << std::endl; > > stream.close(); > char c; > std::cin >> c; > } > //**************************************************** > > Link Error: > > ------ Build started: Project: support library, Configuration: Debug > Win32 ------ > Compiling... > Methods.cpp > Creating library... > Build log was saved at "file://c:\Test\BuildLog.htm" > support library - 0 error(s), 0 warning(s) > ------ Build started: Project: testerParse, Configuration: Debug Win32 > ------ > Linking... > support library.lib(Methods.obj) : error LNK2019: unresolved external > symbol "class std::basic_string<char,struct > std::char_traits<char>,class std::allocator<char> > const __cdecl > methodDoesNotExist(void)" (?methodDoesNotExist@@YA?BV?$basic_string(a)DU? > $char_traits@D(a)std@@V?$allocator@D@2@@std@@XZ) referenced in function > "class std::basic_string<char,struct std::char_traits<char>,class > std::allocator<char> > const __cdecl method2(class > std::basic_istream<char,struct std::char_traits<char> > &)" (? > method2@@YA?BV?$basic_string(a)DU?$char_traits@D(a)std@@V? > $allocator@D@2@@std@@AAV?$basic_istream(a)DU?$char_traits@D(a)std@@@2@@Z) > C:\Test\testerParse.exe : fatal error LNK1120: 1 unresolved externals > Build log was saved at "file://c:\Test\BuildLog.htm" > testerParse - 2 error(s), 0 warning(s) > ========== Build: 1 succeeded, 1 failed, 0 up-to-date, 0 skipped > ========== I am no expert at this, but I think you might take a look at Function-Level Linking (/Gy switch in VC++) -- David Wilkinson Visual C++ MVP
From: John N. on 4 Feb 2010 19:04 On Feb 3, 9:54 am, David Wilkinson <no-re...(a)effisols.com> wrote: > John N. wrote: > > I have stumbled across a problem involving linking to a static library > > that I was hoping someone could help me with. > > > I want to create a static library which contains various methods that > > I will use from other code. In my simple example case, I try to call > > one of the two library methods from main(). Everything compiles > > correctly. However, when linking, I get the link error shown below. > > > The source files (Methods.h, Methods.cpp, Tester.cpp) for my simple > > example are typed out at the end of this post. > > > Methods.h and Methods.cpp are used to build a static library named > > support library.lib, while Tester.cpp is the main() which uses one > > of the two methods (method1) defined in Methods.cpp. > > > The other method in the static library (method2) in Methods.cpp is > > not referenced by main(). It in turn references a method > > (methodDoesNotExist) that is declared in Methods.h, but is not > > defined in Methods.cpp. Thus, the static library compiles and is > > built with no errors, yet when I go to link it with the main() I get > > the link error shown below. > > > Why does the linker give me this link error since I am not trying to > > use method2? > > > One way to fix the problem would be to create separate .cpp/h files > > for each of the methods and then use all those files to create the > > static library. > > > Is there any way to keep all the methods in the same file (for ease of > > maintenance), yet have the linker only resolve references that are > > used? > > > Thank you. > > John N. > > > Small example source files begin here: > > > // Methods.h > > //************************************************* > > #include <string> > > #include <istream> > > > const std::string method1( std::istream& stream_ ); > > const std::string method2( std::istream& stream_ ); > > const std::string methodDoesNotExist(); > > //************************************************* > > > // Methods.cpp > > //********************************** > > #include <string> // std::string > > #include <istream> // std::istream > > #include "Methods.h" // ::Methods_xxx > > > const std::string > > method1( std::istream& stream_ ) > > { > > return "from method1"; > > } > > > const std::string > > method2( std::istream& stream_ ) > > { > > return methodDoesNotExist(); > > } > > //********************************** > > > // Tester.cpp > > //**************************************************** > > #include "Methods.h" > > #include <fstream> > > #include <iostream> // std::cout > > #include <string> > > > int main(){ > > std::ifstream stream; > > stream.open("testerParse.txt"); > > > std::cout << ::method1( stream ) << std::endl; > > > stream.close(); > > char c; > > std::cin >> c; > > } > > //**************************************************** > > > Link Error: > > > ------ Build started: Project: support library, Configuration: Debug > > Win32 ------ > > Compiling... > > Methods.cpp > > Creating library... > > Build log was saved at "file://c:\Test\BuildLog.htm" > > support library - 0 error(s), 0 warning(s) > > ------ Build started: Project: testerParse, Configuration: Debug Win32 > > ------ > > Linking... > > support library.lib(Methods.obj) : error LNK2019: unresolved external > > symbol "class std::basic_string<char,struct > > std::char_traits<char>,class std::allocator<char> > const __cdecl > > methodDoesNotExist(void)" (?methodDoesNotExist@@YA?BV?$basic_string(a)DU? > > $char_traits@D(a)std@@V?$allocator@D@2@@std@@XZ) referenced in function > > "class std::basic_string<char,struct std::char_traits<char>,class > > std::allocator<char> > const __cdecl method2(class > > std::basic_istream<char,struct std::char_traits<char> > &)" (? > > method2@@YA?BV?$basic_string(a)DU?$char_traits@D(a)std@@V? > > $allocator@D@2@@std@@AAV?$basic_istream(a)DU?$char_traits@D(a)std@@@2@@Z) > > C:\Test\testerParse.exe : fatal error LNK1120: 1 unresolved externals > > Build log was saved at "file://c:\Test\BuildLog.htm" > > testerParse - 2 error(s), 0 warning(s) > > ========== Build: 1 succeeded, 1 failed, 0 up-to-date, 0 skipped > > ========== > > I am no expert at this, but I think you might take a look at > > Function-Level Linking (/Gy switch in VC++) > > -- > David Wilkinson > Visual C++ MVP David, Thank you for the response. I tried changing the option in my solution (for both the .lib and .exe) under "Project Properties->Code Generation->Enable Function- Level Linking->/Gy (Yes)", however, I still get the same linker error (as seen in first post) when I build the project (in both debug and release mode, just in case that might make any difference). Thanks, John
From: Tim Roberts on 7 Feb 2010 14:08 "John N." <ortp21(a)gmail.com> wrote: > >I was actually hoping there was a means for the compiler to package >things in the obj file so that separate functions are separate (the >obj would effectively be a static library with an obj name). I guess >this does not exist. No. The unit of linkage is an object file, not a function. There are very good reasons for this. "Functions" are not a linker concept. The division of code into units called "functions" is simply an arbitrary convention of whatever compiler you're using. In the object file, you just have a sequence of machine language instructions that happens to have public names attached every now and then. In many assembler programs, for example, the code is not so neatly packaged. Functions might flow into other functions, or jump into other parts of the object file. Now, it's true that the linker can usually tell whether an object file was created by a C compiler. Knowing that, and knowing the internals of the compiler, it can make certain assumptions about the organization of the code. If you specify linker optimizations with the /OPT flag, it will attempt to do that. >Does this mean that an entire C++ class is brought into an exe even if >only a small percentage of it is used? Generally, if the class is implemented in a single source file, yes. Note that this MUST be true for the virtual functions in a class. The virtual function table for a class has a pointer to every virtual function it implements. Thus, there will ALWAYS be a reference to every virtual function. There's no way to tell whether a particular virtual function will ever be called without simulating the executing the code, and Turing gets in the way of that. -- Tim Roberts, timr(a)probo.com Providenza & Boekelheide, Inc.
From: John N. on 8 Feb 2010 15:50 On Feb 7, 1:08 pm, Tim Roberts <t...(a)probo.com> wrote: > "John N." <ort...(a)gmail.com> wrote: > > >I was actually hoping there was a means for the compiler to package > >things in the obj file so that separate functions are separate (the > >obj would effectively be a static library with an obj name). I guess > >this does not exist. > > No. The unit of linkage is an object file, not a function. There are very > good reasons for this. "Functions" are not a linker concept. The division > of code into units called "functions" is simply an arbitrary convention of > whatever compiler you're using. In the object file, you just have a > sequence of machine language instructions that happens to have public names > attached every now and then. > > In many assembler programs, for example, the code is not so neatly > packaged. Functions might flow into other functions, or jump into other > parts of the object file. > > Now, it's true that the linker can usually tell whether an object file was > created by a C compiler. Knowing that, and knowing the internals of the > compiler, it can make certain assumptions about the organization of the > code. If you specify linker optimizations with the /OPT flag, it will > attempt to do that. > > >Does this mean that an entire C++ class is brought into an exe even if > >only a small percentage of it is used? > > Generally, if the class is implemented in a single source file, yes. > > Note that this MUST be true for the virtual functions in a class. The > virtual function table for a class has a pointer to every virtual function > it implements. Thus, there will ALWAYS be a reference to every virtual > function. There's no way to tell whether a particular virtual function > will ever be called without simulating the executing the code, and Turing > gets in the way of that. > -- > Tim Roberts, t...(a)probo.com > Providenza & Boekelheide, Inc. Tim, Thank you for the informative post. >There's no way to tell whether a particular virtual function > will ever be called without simulating the executing the code, and Turing > gets in the way of that. If a virtual method is not referenced in the entire executable, then why is it required?
|
Next
|
Last
Pages: 1 2 Prev: Using signal in a runtime loaded DLL Next: "PORTING C" > How to assign a value to a define statement? |