I'm trying to add SDL2 as a library to my project. I want to link it statically. I'm new to c++.
1 - Why does the SDL website recommend linking dynamically whenever possible?
I understand the benefits of dynamic libs. However, assuming users will have all the libraries you need already installed and ready to go in their system is a pretty big assumption IMO.
The only case where linking dynamically sounds like a good idea to me is where you are using well know libraries that ship with the OS/platform.
https://wiki.libsdl.org/Installation
2 - Linking dynamically seems to automatically find the intrinsic dependencies of (SDL2 and SDL2_image). Linking statically does not. Why is this the case? Here's my FindSDL2_image.cmake file
find_path(SDL2_IMAGE_INCLUDE_DIR SDL_image.h)
include_directories(${SDL2_IMAGE_INCLUDE_DIR})
# PREFER STATIC LIBRARIES ########
# cmake respects the order of extensions when looking for libraries
SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
# ------------------- ########
find_library(SDL2_IMAGE_LIBRARY NAMES SDL2_image PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX})
set(SDL2_IMAGE ${SDL2_IMAGE_LIBRARY})
This links sdl2_image statically. It doesn't link properly because Undefined symbols:
"_png_set_strip_16", referenced from:
_IMG_LoadPNG_RW in libSDL2_image.a(IMG_png.o)
"_png_set_write_fn", referenced from:
_IMG_SavePNG_RW_libpng in libSDL2_image.a(IMG_png.o)
"_png_write_png", referenced from:
_IMG_SavePNG_RW_libpng in libSDL2_image.a(IMG_png.o)
If I remove the section ### PREFER STATIC LIBRARIES ## on the cmake file. It links dynamically and everything works as expected. Why when linking dynamically the intrinsic dependencies are resolved but not when linking statically?
----UPDATE----
I was able to link sdl2_image statically by including its dependencies explicitly
find_library(PNGLIB png)
find_library(JPEG jpeg)
find_library(TIFF tiff)
find_library(WEBP webp)
find_library(LZ z)
target_link_libraries(smb ${SDL2} ${PNGLIB} ${JPEG} ${TIFF} ${WEBP} ${SDL2_IMAGE} ${LZ})
However, this will not scale well for me.
Figuring out what these dependencies took a bit of guesswork and googling. Ideally, I'd like CMAKE to pull these in automatically.
it looks like there are several questions, I'll try my best to answer the question step by step:
Why does the SDL website recommend linking dynamically whenever
possible
One of the reason to link you application dynamically against a library is to decouple the application from the library (it is called shared library / .so in this case). You could update your library without the necessity of recompiling your application code. E.g. in case you have finished your project, and your client have your application running, I suppose, it is not likely that you want to recompile your application code, once there is a bug fix of the underlying library you are using.
On the other side, by linking your application statically, you're binding your application with that library (.lib or .a form). Means every changes in the library will cause you to recompile your code. Sometime this is wished, e.g. you have provide your client a warranty of your application, usually you want to be sure that no future problem with your library would cause your application to be crashed.
I have a short example code to understand this better:
CMakeLists.txt:
cmake_minimum_required (VERSION 3.0)
project(linkageLibrary)
set(STATIC_LIB lib_static)
set(SHARE_LIB lib_share)
set(STATIC_OTHER_LIB lib_otherstatic)
set(SHARE_OTHER_LIB lib_othershare)
add_library(${STATIC_LIB} STATIC ${STATIC_LIB}.cpp)
add_library(${SHARE_LIB} SHARED ${SHARE_LIB}.cpp)
# not yet in usage...
add_library(${STATIC_OTHER_LIB} STATIC ${STATIC_OTHER_LIB}.cpp)
add_library(${SHARE_OTHER_LIB} SHARED ${SHARE_OTHER_LIB}.cpp)
add_executable(${CMAKE_PROJECT_NAME} main.cpp)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ${${CMAKE_PROJECT_NAME}_SOURCE_DIR})
target_link_libraries(${CMAKE_PROJECT_NAME} ${STATIC_LIB} ${SHARE_LIB})
file(WRITE ${CMAKE_BINARY_DIR}/exchangeShareLibrary.sh "
echo \"before exchange the static library\"
${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME} &&
mv ${CMAKE_BINARY_DIR}/lib${SHARE_LIB}.so ${CMAKE_BINARY_DIR}/lib${SHARE_LIB}.so.bk &&
cp ${CMAKE_BINARY_DIR}/lib${SHARE_OTHER_LIB}.so ${CMAKE_BINARY_DIR}/lib${SHARE_LIB}.so &&
echo \"after the shared library has been changed\" &&
${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}")
file(WRITE ${CMAKE_BINARY_DIR}/exchangeStaticLibrary.sh "
echo \"before exchange the static library\"
${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME} &&
mv ${CMAKE_BINARY_DIR}/lib${STATIC_LIB}.a ${CMAKE_BINARY_DIR}/lib${STATIC_LIB}a.bk &&
cp ${CMAKE_BINARY_DIR}/lib${STATIC_OTHER_LIB}.a ${CMAKE_BINARY_DIR}/lib${STATIC_LIB}.a &&
echo \"after the static library has been changed\" &&
${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}")
main.cpp:
#include <iostream>
#include "lib.hpp"
using namespace std;
int main() {
printStaticLib();
printShareLib();
return 0;
}
lib.hpp:
#pragma ONCE
void printStaticLib();
void printShareLib();
lib_static.cpp:
#include <iostream>
#include "lib.hpp"
using namespace std;
void printStaticLib() {
cout << "linkage of lib_static" << endl;
}
lib_share.cpp:
#include <iostream>
#include "lib.hpp"
using namespace std;
void printShareLib() {
cout << "linkage of lib_share" << endl;
}
lib_otherstatic.cpp:
#include <iostream>
#include "lib.hpp"
using namespace std;
void printStaticLib() {
cout << "linkage of the other lib_static with other text" << endl;
}
lib_othershare.cpp:
#include <iostream>
#include "lib.hpp"
using namespace std;
void printShareLib() {
cout << "linkage of the other lib_share with other text" << endl;
}
if you run the generated scripts, you'll notice the printShareLib() will output differently after the .so get exchange, but not the printStaticLib(). (Try to make again without clean-up, if you now execute ./linkageLibrary, you'll get this time also other output for the printStaticLib(). Can you guess why?)
to your second issue:
2 - Linking dynamically seems to automatically find the intrinsic dependencies of (SDL2 and SDL2_image). Linking statically does not. Why is this the case?
without knowing your system setup, I guess the .a static library couldn't be found by your build system. Try to find where it is, and eventually put find_library(SDL2_IMAGE_LIBRARY NAMES SDL2_image HINTS ${_YOUR_SDL2_INSTALLATION_PATH})link
now back to your question, why SDL2 suggested to be linked dynamically, well it is the decision of the library developer, as you could read in his README
Please also refer this blog of how using SDL2 with CMake
A Static library is merely a collection of compiled object files. It does not have any additional information about its dependent libraries. You can use the ar -t <static_lib> command to view the contents of a static library. So if you need to link your executable to a static library, you have to provide the names and paths of all its dependent libraries.
For example: Consider two static libs, A and B and assume that A depends on B. Then if want your exe C to link to A, then your link statement should contain both A and B. Then only all the symbols will defined properly.Linker: C ===> A and B
A dynamic library is different and more intelligent than a static. It is of ELF format and it's headers have information about its dependent shared libraries. This can be viewed by issuing the ldd <dynamic_lib> command on it. Also dynamic loader knows at runtime to pick the dependent libraries from the standard locations. If it can't find, it will give an error. In your case, you will find the information about the dependent libraries of your dynamic library in your ldd output and presumably, all those libraries will be in a standard location. That is the reason you are not finding an error, when you are trying to dynamically link.
Here are some useful links to know more about this,
https://renenyffenegger.ch/notes/development/dynamic-loader
https://amir.rachum.com/blog/2016/09/17/shared-libraries/
When you do a find_package in CMake will search for a Findxxx.cmake file in some CMAKE-defined paths.
The command has two modes by which it searches for packages: “Module” mode and “Config” mode. Module mode is available when the command is invoked with the above reduced signature. CMake searches for a file called Find.cmake in the CMAKE_MODULE_PATH followed by the CMake installation.
(https://cmake.org/cmake/help/latest/command/find_package.html)
So you have to define your own FindSDL2.cmake which will tell where is the library. (https://cmake.org/cmake/help/v3.17/manual/cmake-developer.7.html)
And you need to say to find_package to search for your own FindSDL2.cmake. You can pass a path to find_package to perform this.
If you make CMake use your file, the variables ${SDL2_INCLUDE_DIRS} and ${SDL2_LIBRARIES} you will be the one you have defined in your file.
A couple of possibilities here ..
The easiest explanation is that you have a dynamic libpng.so.x installed somewhere where your dynamic linker can find it (/usr/lib, /usr/local/lib, etc), but don't have a static libpng.a. The answer in that case would be to install a static libpng.a and see if cmake's magic can resolve it.
The next easiest explanation is that there is no libpng.* on your system and there is some dynamic late binding going on. This can happen if, for instance, the software that you are building is also building libpng.* in which case the late binding will allow you to successfully dynamically link your application to it, even though libpng actually has not yet been installed in /usr/lib or /usr/local/lib or wherever the software you are building will eventually put it. This is sort of a chicken-and-egg situation. You can figure this out by issuing "ldd foo" where "foo" is the name of your application. The output will be a grocery list of all the things the dynamic linker needs to fetch for your executable, libpng should be in the list and there should be a resolved path listed for it, if not it's possible that your application may start but subsequently crash if for instance png_write_png() is at some point invoked. How to workaround this would be to install the libpng.* libraries that your application is expecting, prior to building.
Hope this helps a bit :)
Related
So recently I've been trying out autotools to build a C++ Library. Originally I was just working on pure custom classes, which is quite easy to just #include and then compile with g++. But when I want to write some custom functions for the library, I've learnt that it's a bad practice to write functions within header file, but rather I should declare it in header then wrote it in a separate .cpp file. Which later I've tried and successfully compiled with g++ ./lib/**/*.cpp src/main.cpp.
So basically my project structure is that codes are put under src/, headers are under include/ and functions are put under lib/. And following is my src/Makefile.am
AUTOMAKE_OPTIONS = subdir-objects foreign
bin_PROGRAMS = main
include_HEADERS = -I../include/**/*.hpp
main_SOURCES = -I../lib/**/*.cpp main.cpp
And for the endpoints' directory (under lib/) I have something like following
main_SOURCES = stdout.cpp
But it gave me error that no program named main, so I figured maybe all those function files has to be compiled first, so I changed them into
noinst_PROGRAMS = stdout
stdout_SOURCES = stdout.cpp
But then they gave me the following error
/usr/sbin/ld: /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/../../../../lib/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
I know that the error meant that there's no main() written in the file, but since it's a library function file, it doesn't meant to have a main(), it's meant to be called by other file (like main.cpp). And to here I'm stuck.
I've tried to find documentation online, but it seems that most of them are targeted at C programs instead of C++, which I'm not sure if those steps are compatible. And I remember C++ libraries are compiled into .so or .o file while most tutorials seems to be using .la files.
MWE
src/main.cpp
#include"../include/conn/bash/stdout.hpp"
#include<string>
#include<iostream>
int main() {
std::string o=d::conn::bash::exec("ls");
std::cout << o << std::endl;
return 0;
}
include/conn/bash/stdout.hpp
#ifndef __CONN_BASH_O__
#define __CONN_BASH_O__
#include<string>
namespace d { namespace conn { namespace bash {
std::string exec(const char*);
}}}
#endif
lib/conn/bash/stdout.cpp
#include"../../../include/conn/bash/stdout.hpp"
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
std::string d::conn::bash::exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
// https://stackoverflow.com/a/478960/8460574
Compiled and tested with g++ ./lib/**/*.cpp src/main.cpp
I've tried to find documentation online, but it seems that most of
them are targeted at C programs instead of C++,
"Most of them" suggests that you are searching out tutorials. Documentation would be the Automake manual, which you would be well advised to read. It covers these topics and many more that you will want to know about as you continue with the Autotools, and with Automake in particular. At minimum, you should know how to find the manual so as to consult it at need. Tutorials and guides can be helpful, but they should be regarded as supplements to the manual, not primary sources.
which I'm not sure if
those steps are compatible.
They mostly are. The main thing to be aware of is that command-line options for the C compiler are specified via a CFLAGS primary (see below), whereas those for the C++ compiler are specified via a CXXFLAGS primary.
And I remember C++ libraries are compiled
into .so or .o file while most tutorials seems to be using .la files.
You seem to be confused. The formats associated with those extensions are not language-specific, and .o does not designate a library at all.
.o is the conventional extension for the object file arising from compiling a single source file. These can be linked into an executable, or they can be gathered together into a library, but they are not libraries themselves.
Conventional UNIX library extensions are .a for static libraries and .so for shared libraries. This applies to any language that can be used to build general-purpose link libraries, including C, C++, Fortran, and a variety of others.
The .la extension is something else. It designates a libtool library. Libtool is another of the autotools, focused on abstracting system-specific details of building and using libraries. This is again language independent. Building a libtool library will cause either a corresponding static library, a corresponding shared library, or both to be built and installed, depending the options specified in the Autotooling and / or on the configure command line.
You should use libtool if you are building shared libraries with the Autotools. You may also use it if you are building only static libraries (.a), but it is a bit simpler in that case to leave libtool out of the picture.
As for the specific question posed, you write:
And for the endpoints' directory (under lib/) I have something like
following
main_SOURCES = stdout.cpp
But it gave me error that no program named main,
Always present the actual text of the error message (as text), rather than a paraphrase. If you have to ask a question about it here, then there is a significant risk that your understanding of the message is incomplete or wrong, and therefore that your paraphrase is misleading.
In this case, I am relatively confident that Automake's complaint was that there is no target named "main". The line you've given specifies a source list for such a target, but Automake does not find that target defined in that Makefile.am file. The difference between "program" and "target" is a bit subtle, but significant.
Supposing that you are trying to build a convenience library -- that is, one that groups functions for compile-time use in building other targets, but is not intended to be installed as a standalone library* -- you could get it with something like:
noinst_LIBRARIES = libendpoints.a
That consists of thee main pieces:
LIBRARIES is the "primary", specifying what kind of definition is being given. In this case, it is the definition of a list of static library targets included in the project.
libendpoints.a specifies the name of a (static library) target. This is an external name: the build will generate a file by this name in the build tree. Do make a habit of using standard naming conventions for this, such as I demonstrate.
noinst specifies where the built target will be installed by make install. This particular value is a special one indicating that the target will not be installed at all. If you wanted it installed in the configured libdir then you would instead say lib.
The properties of that target must be given by other definitions, based on a munged form of its name. For instance, its source list might look like this:
libendpoints_a_SOURCES = stdout.cpp
That again consists of three pieces:
SOURCES is again the primary. In this case, it says that the definition provides a source list for some target.
libendpoints_a identifies the target whose source list is being given. It is a munged form of the target name, with characters that cannot appear in variable names replaced by '_' characters.
stdout.cpp is the (single-element) source list.
To use that, the main program's properties would also need to specify that the library should be linked. That would mean something along these lines in the Makefile.am in which the main program target is defined:
main_LDADD = lib/endpoints/libendpoints.a
That is again a three-part definition, whose interpretation I leave as an exercise.
*And if you wanted a static library that does get installed to the system then you would swap out the "noinst" for a prefix that identifies the installation location, such as "lib". And there is a slightly different form for libtool-mediated libraries, including shared libaries.
If you're just defining a convenience target for you library, you should be able to do so by declaring it as noinst_LIBRARIES = libmine.a and then declaring it as a stdout_LIBADD.
But most likely, if you don't want this as an installed library, you just want to list the sources directly in a single, non-recursive Makefile.am file, see https://autotools.io/automake/nonrecursive.html
If you do want your library to be installable, then you want to use libtool: https://autotools.io/libtool/index.html
I have two C++ modules: A and B, where B links to a set of static libs lib*.a (I use * here to mean a set of lib files) and A links to B.
I have CMakeLists.txt for B:
add_library(B STATIC B.cpp)
target_include_directories(B PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} "/path/to/headers/directory/for/lib*.a")
link_directories("Path/to/directory/contains/lib*.a")
target_link_libraries(B PRIVATE lib*)
and CMakeLists.txt for A:
add_library(A STATIC A.cpp)
target_include_directories(A PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} "/path/to/headers/for/libB.a") # compiler outputs libB.a when target name is B
link_directories("Path/to/directory/contains/libB.a")
target_link_libraries(A PRIVATE B)
Everything works fine, until I try to make A a shared lib, then I got error from the linker saying cannot find -l*. I believe the reason is that when I set A to be shared, the compiler looks for shared lib, which is not available.
The thing I don't understand:
B is already a static lib, why the linker needs lib*?
why compiler looks for shared lib when I set A to be shared? I thought even a shared A can be linked to static libs
I do want to note that in A.cpp, I have #include B.hh at the top, and B.hh further includes the headers for lib*.a, that is why I have target_include_directories(B PUBLIC...)
Your initial setup was already not working, but you did not see the error until switching to a shared library.
The reason for this is that all your target_link_libraries dependencies on A and B were not actually processed at all so long as both were static libraries. This has to do with what a static library is: Just a bunch of object files packed together into a single file. A static library is not linked, hence any build dependencies that concern the linker (such as linking in additional static libraries as dependencies) will not get resolved. The build system will keep track of them, but if they are missing, you will not notice unless you actually pass those libraries to something that is actually being linked - such as an executable or, in your case now, a shared library.
Since it can be a bit embarassing to have invisible unresolved dependencies like this, idiomatic CMake will have you model things differently. You never pull in static dependencies directly, instead you use an approach like the following: At the lowest layer, you have a find_library call that finds any external pre-built dependencies on the system (the lib* in your example). You then wrap that up into an imported target so that you never have to touch the raw library path again. To smoothen things out, you can hide all of this inside a find package script, so that your code only ever sees a find_package call that provides a lib* target and don't worry about the internals.
You then model all of your library interdepencies through target dependencies only. Such an approach has several advantages that make it more robust: If CMake can't find the lib*, it will tell you right away when the find_package call fail, instead of waiting until you're trying to link like it does now. By only specifying target-based dependencies, you ensure that the build is actually consuming the libraries that it was configured with (which is very much not ensured with the link_directories based approach you're having now).
I am new to CPP, to GUROBI and specially to CMAKE. I am working on a project and I am trying to compile a C++ program, that needs to link to the GUROBI external libraries libgurobi81.so and libgurobi_c++.a as explained in the GUROBI site here and here.
The structure of my cmake and my project is something like this:
-folder1
--src
---cmake
--gurobi
---lib
----libgurobi81.so
----libgurobi_c++.a
My code compiles correctly, but it only fails when linking with the libraries.
I tried to make CMAKE to find the libraries:
find_library(C_GUROBI_LIB NAMES libgurobi81.so gurobi81 gurobi81_light
PATHS ${LD_LIBRARY_PATH}
/path/to/folder1/gurobi/lib/
)
find_library(CPP_GUROBI_LIB NAMES gurobi_c++
PATHS ${LD_LIBRARY_PATH}
/path/to/folder1/folder1/gurobi/lib/
)
and then to print it:
message("C_GUROBI_LIB points to " ${C_GUROBI_LIB})
message("CPP_GUROBI_LIB points to " ${CPP_GUROBI_LIB})
However, even if the library is in that folder CMAKE do not find it and shows nothing:
C_GUROBI_LIB points to
CPP_GUROBI_LIB points to
I found a possible solution, adapted from here:
set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
I had some other issues, for example the library was compiled for 64 bits, and also that CMAKE did not allow to add Shared files. So I got to change some parameters, but even with that, CMAKE did not found the file.
PROBLEM: I would like to ignore 'dll not found' errors and continue code execution that does not rely on that library.
I understand this is asking alot, but there's no definitive guide on shared libraries and the mess of conversations out there are confusing. I have gathered that there are three types of libraries that CMake is aware of:
Static: Linked into executable on compile.
Shared: UNIX: loadable whenever, WINDOWS: requires a symbols STATIC library to be linked on compile that maps out the DLL.
Module: Runtime loaded shared library, of which I'm still in the process of understanding.
I'm using the CMake 'GenerateExportHeader' to make my life easier in producing shared libraries. This works. I can even version those libraries to change them on the fly. What I'm having trouble figuring out, however, is how to check and possibly ignore the error if the dll is not found:
"The code execution cannot proceed because xxx.dll was not found. Reinstalling the program may fix this problem."
I have tried putting try/catch blocks in the include/object creation. Google foo didn't find anything.
I have looked into "MODULE" type shared library, but I was hoping to avoid the mess that is '__declspec' and loadable libraries.
CMake's 'GenerateExportHeader' is very very nice, and if what I'm asking for isn't possible without manually exporting symbols that's fine, but I thought I might ask the gurus out there.
So.... The code:
CMakeLists.txt:
...
set(BUILD_SHARED_LIBS ON)
set(BUILD_TYPE SHARED)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
include(GenerateExportHeader)
...
# Create the library.
add_library(${NAME} ${BUILD_TYPE}
${SOURCES}
)
# Visual Studio Source Tree and filters.
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})
set_property(TARGET ${NAME} PROPERTY FOLDER "${NAME}")
if(BUILD_SHARED_LIBS)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
GENERATE_EXPORT_HEADER(${NAME}
BASE_NAME ${NAME}
EXPORT_MACRO_NAME ${NAME}_EXPORTS
EXPORT_FILE_NAME ${NAME}_EXPORTS.h
STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC)
endif(BUILD_SHARED_LIBS)
target_include_directories(${NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/public>
$<INSTALL_INTERFACE:public>
PRIVATE private
)
# Link to other libraries.
target_link_libraries(${NAME}
${EXAMPLE_LIBRARY}
)
# 'make install' to correct locations.
install(TARGETS ${NAME} EXPORT ${NAME}Config
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin) # For windows.
install(DIRECTORY public/ DESTINATION include)
# 'public'/ project, 'include' for install.
# Importable from the install directory.
# Configs in per-project dir.
install (EXPORT ${NAME}Config DESTINATION share/${NAME}/cmake)
# Importable from the build directory.
export(TARGETS ${NAME} FILE ${NAME}Config.cmake)
# Library Testing/Future unit tests.
set(TESTING_PRIVATE
Tests/Main.cpp
)
set(TESTING_PUBLIC
)
set(TESTING_COLLECTIVE
${TESTING_PRIVATE}
${TESTING_PUBLIC}
)
add_executable(${NAME}Develop
${TESTING_COLLECTIVE}
)
set_property(TARGET ${NAME}Develop PROPERTY FOLDER "${NAME}")
target_include_directories(${NAME}Develop
PUBLIC ${CMAKE_BINARY_DIR}/exports
)
if(NOT BUILD_MODULAR_LIBS)
target_link_libraries(${NAME}Develop
${NAME}
)
endif(NOT BUILD_MODULAR_LIBS)
My code does not have anything specific in it, so for the purposes of this question I simplified a test case.
library.h:
#pragma once
namespace Library
{
class Library
{
public:
void testing();
};
} // namespace Library
Library.cpp:
#include <iostream>
#include "Library.h"
namespace Library
{
void Library::testing()
{
std::cout << "Library API: Hello, world!.... VERSIONED!" << std::endl;
}
} // namespace Library
Test/Main.cpp:
#include <iostream>
#include <conio.h>
// Tried different error handling, I think I need preprocessors here for this... google didn't help.
// I feel that I should be referencing the DLL, not the header
// and I couldn't find information in wikis or CMake documentation.
#include "Library.h"
int main(int argc, char const *argv[])
{
// The same applies for these two lines.
Library::Library test;
test.testing();
std::cout << "Press any key to exit..." << std::endl;
_getch();
return 0;
}
WHAT I HAVE TRIED:
Putting try/catch blocks around code that references the library. EDIT: Yes I know this is bad and probably would never work, but I didn't know if something internal might be calling a library load.
Compiling a version of my program with and without the option libraries. (Honestly... this is bad... very bad... preprocessor directives can solve this, but this means each person were they to want a tailored version without certain libraries would have to build themselves rather than just dropping the dlls they'd like in there, which is what I would like to do.)
Manual '__declspec' declarations to do this manually, which works but what I would like (if possible) to avoid. There's enough information out there that I was able to piece this together, and am willing to do, but the idea really is to write the code WITH classes just like the executable or a library in what (in c++ terms) would be called plain english.
That last point is really what I'm trying to accomplish. I'd like to be able to write c++ code, and make it readable to other developers, without having to manage some of the more complicated features including platform specific shared library loading.
I've been recently reading about static and dynamic linking and I understood the differences and how to create static and dynamic library and link it to my project
But, a question came to my mind that I couldn't answer or find answer for it as It's a specific question ... when I compile my code on linux using the line
#include <stdio.h>
int main()
{
printf("hello, world!\n");
}
compiling using this command
[root#host ~]# gcc helloworld.c -o helloworld
which type of linking is this??
so the stdio.h is statically or dynamically linked to my project???
Libraries are mostly used as shared resources so, that several different programs can reuse the same pre-compiled code in some manner. Some libraries come as standard libraries which are delivered with the operating system and/or the compiler package. Some libraries come with other third party projects.
When you run just gcc in the manner of your example, you really run a compiler driver which provides you with few compilation-related functions, calling different parts of the compilation process and finally linking your application with a few standard libraries. The type of the libraries is chosen based on the qualifiers you provide. By default it will try to find dynamic (shared) libraries and if missing will attempt for static. Unless you tell it to use static libs only (-static).
When you link to project libraries you tell the gcc/g++ which libraries to use in a manner (-lname). In such a way it will do the same as with the standard libraries, looking for '.so' first and '.a' second, unless -static is used. You can directly specify the path to the full library name as well, actually telling it which library to use. There are several other qualifiers which control the linking process, please look man for 'g++' and 'ld'.
A library must contain real program code and data. The way it is linked to the main executable (and other libraries) is through symbol tables which are parts of the libraries. A symbol table contains entries for global functions an data.
There is a slight difference in the structure of the shared and static libs. The former one is actually a pre-linked object, similar to an executable image with some extra info related to the symbols and relocation (such a library can be loaded at any address in the memory and still should work correctly). The static library is actually an archive of '.o' files, ready for a full-blown linking.
The usual steps to create a library is to compile multiple parts of your program into '.o' files which in turn could be linked in a shared library by 'ld' (or g++) or archived in .a with 'ar'. Afterwards you can use them for linking in a manner described above.
An object file (.o) is created one per a .cpp source file. The source file contains code and can include any number of header files, as 'stdio.h' in your case (or cstdio) or whatever. These files become a part of the source which is insured by the cpp preprocessor. The latter takes care of macros and flattening all the #include hierarchies so that the compiler sees only a single text stream which it converts into '.o'. In general header files should not contain executable code, but declarations and macros, though it is not always true. But it does not matter since they become welded with the main source file.
Hope this would explain it.
which type of linking is this?? so the stdio.h is statically or
dynamically linked to my project???
stdio.h is not linked, it is a header file, and contains code / text, no compiled objects.
The normal link process prefers the '.so' library over the '.a' archive when both are found in the same directory. Your simple command is linking with the .so (if that is in the correct path) or the .a (if that is found in a path with no .so equivalent).
To achieve static linking, you have several choices, including
1) copy the '.a' archive to a directory you create, then specify that
directory (-L)
2) specify the path to the '.a' in the build command. Boost example:
$(CC) $(CC_FLAGS) $< /usr/local/lib/libboost_chrono.a -o $# $(LIB_DIRs) $(LIB_NMs)
I have used both techniques, I find the first easier.
Note that archive code might refer to symbols in another archive. You can command the linker to search a library multiple times.
If you let the build link with the .so, this does not pull in a copy of the entire .so into the build. Instead, the .so (the entire lib) is loaded into memory (if not already there) at run-time, after the program starts. For most applications, this is considered a 'small' start-up performance hit as the program adjusts its memory map (auto-magically behind the scenes) Note that the app itself can control when to load the .so, called dynamic library.
Unrelated:
// If your C++ 'Hello World' has no class ... why bother?
#include <iostream>
class Hello_t {
public:
Hello_t() { std::cout << "\n Hello" << std::flush; }
~Hello_t() { std::cout << "World!" << std::endl; }
void operator() () { std::cout << " C++ "; }
};
int main(int, char**) { Hello_t()(); }