Why cant libgtest.a be moved to a different location? - cmake

Dear gtest/cmake experts:
Is there a way to use the gtest archive libgtest.a from a location that is different from the location where it was created?
Here's my working case:
libgtest location: /usr/lib/x86_64-linux-gnu/libgtest.a and also in /usr/src/googletest/googletest/lib/libgtest.a
(I'm not sure why/how it is present in two locations. Its possible that I copy/pasted it long ago). The source code and CMakeLists etc for gtest are under /usr/src/googletest/
CMakeLists.txt:
< .. link other libraries, dependencies etc .. >
target_link_libraries(Application PRIVATE libgtest.a)
Note: Application is being built as a "shared object". libgtest.a is static. But this works fine.
Non-working case:
I copied libgtest.a to another location:
/my/project/dir/depends/pkgs/libgtest.a
CMakeLists.txt:
< .. link other libraries, dependencies etc .. >
target_link_libraries(Application PRIVATE /my/project/dir/depends/pkgget/libgtest.a)
This throws a LOT of "relocation/ fPIC" related errors. For example:
ld.lld: error: relocation R_X86_64_PC32 cannot be used against symbol testing::FLAGS_gtest_output[abi:cxx11]; recompile with -fPIC
>>> defined in ../../depends/lib/libgtest.a(gtest-all.cc.o)
>>> referenced by gtest-all.cc
>>> gtest-all.cc.o:(testing::internal::UnitTestOptions::GetOutputFormat[abi:cxx11]()) in archive ../../depends/lib/libgtest.a
ld.lld: error: relocation R_X86_64_PC32 cannot be used against symbol testing::FLAGS_gtest_output[abi:cxx11]; recompile with -fPIC
>>> defined in ../../depends/lib/libgtest.a(gtest-all.cc.o)
>>> referenced by gtest-all.cc
>>> gtest-all.cc.o:(testing::internal::UnitTestOptions::GetAbsolutePathToOutputFile[abi:cxx11]()) in archive ../../depends/lib/libgtest.a
Questions:
How come there is no problem with relocation/ fPIC in the former
case but there is a problem in the latter case? What gives?
What's the correct way to use the pre-compiled archive from a different
location?
I'm looking forward to your inputs.
Best regards,
--Venk

Related

How to include target include directories transitive through multiple linked libraries

we are working on an embedded project in C/C++ and currently some special needs appeared. Background is there are two compiled libraries which define the same symbols. The compiler allows to create relocatable output modules (with partial linking) and to hide symbols for other compilation units when linking. This also means the output module does not need to have all the symbols defined, this will be done in the final linking. Compiler used is TI LTS1.3.0. I will link directly to the relocatable-section of the manual: https://software-dl.ti.com/codegen/docs/tiarmclang/rel1_3_0_LTS/compiler_manual/linker_description/04_linker_options/linker-output-options.html#stdz0756429
The other part of the project is hardly built on CMake with static libraries which are linked against each other via target_link_libraries.
To get this working I created an "add_executable"-target for each of those both output modules with the same symbols. To those I pass the static-libraries by CMake and get the linked with target_link_libraries.
But now I have a problem. All contents of the static libraries are compiled in each of those output modules. This is unwanted behaviour since as said the final linking does the job of linking the missing stuff - so the static-libraries - to it. This should be done with another add_executable command via CMake as well.
using the target include directories property is not suitable since it only adds the include directories of the given target itself but not of the target the target will include and link against.
So e.g. if you have (pseudo code):
#library A
function( create_libA )
add_library( libA src/A.c )
target_include_directories( libA PUBLIC /inc ) #contains A.h
endfunction()
#library B. different location
function( create_libB LIBA )
add_library( libB src/B.c )
target_link_libraries( libB PUBLIC ${LIBA} )
target_include_directories( libB PUBLIC /inc ) #contains B.h
endfunction()
#target output module with partial linking. Only should link and compile LIBTOBELINKEDIN, not libB. different location.
function( build_part_module LIBB LIBTOBELINKEDIN )
add_executable( outputModuleA src/func.c ) #func.c does include A.h
#following would cause libA and libB also to be compiled and linked in the output due to transitive stuff as I understood, which is unwanted.
target_link_libraries( outputModuleA PUBLIC ${LIBB} ${LIBTOBELINKEDIN} )
#trying this
get_target_property(libBInc ${LIBB} INTERFACE_INCLUDE_DIRECTORIES)
#will only include B.h but not A.h. compilation will fail.
target_include_directories(outputModuleA /inc ${libBInc})
I did not find any solution in Cmake itself to solve this problem. It's confusing me since all the include-directories must be known when the libraries are passed transitive, which is stated in the documentation. But I understand that getting the target include directories of just the passed lib does not include the other ones.
Since target_link_libraries does also not work this way I can only think of a maybe recursive solution? But for that my knowledge is just non-existent.
target_link_libraries with something like HEADERS_ONLY would be helpfull for this job.
Also one can say: if the output module contains all the definitions it won't be a problem, since the linker then knows them and will do its magic.
But this is also unwanted, since we use the generated static-libraries to place them into sections in different regions of the RAM directly. This would then mean to create another linker-script for partial linking which defines sections which then can be again moved. But the more we go this direction, the less we need CMake for it.
Instead of get_target_property use $<TARGET_PROPERTY> generator expression: the property's value, extracted by that expression, already includes transitive propagation:
target_include_directories(outputModuleA PRIVATE
$<TARGET_PROPERTY:libB,INTERFACE_INCLUDE_DIRECTORIES>
)
Note, that generator expressions has limited usage: not all functions expects them. Documentation for target_include_directories clearly states that the command supports generator expressions.

Why doesn't cmake find_package(VTK) find VTK_INCLUDE_DIRS after building VTK from source and installing?

I’m running cmake version 3.23.0-rc1, on ubuntu 20.04.
I built vtk-8.2 from source; cmake, make, then ‘make install’. Now I am trying to find the VTK package for my own application, using cmake’s find_package(VTK). The application’s CMakeLists.txt contains this:
find_package(VTK)
message("VTK_FOUND: ${VTK_FOUND}")
message("VTK_INCLUDE_DIRS: ${VTK_INCLUDE_DIRS}")
message("VTK_LIBRARIES: ${VTK_LIBRARIES}")
Result is that VTK_FOUND=1, VTK_LIBRARIES contains many entries, but VTK_INCLUDE_DIRS is blank/empty. Why would this be?
I do see file /usr/local/lib/cmake/vtk-8.2, which contains many *.cmake files. But I don’t see a corresponding /usr/local/include/cmake directory, despite the presence of /usr/local/include/vtk-8.2. Is that expected? Here is the output:
VTK_FOUND: 1
VTK_INCLUDE_DIRS:
VTK_LIBRARIES: VTK::WrappingTools;VTK::ViewsQt;VTK::ViewsInfovis;VTK::CommonColor;VTK::ViewsContext2D;VTK::loguru;VTK::TestingRendering;VTK::TestingCore;VTK::vtksys;VTK::RenderingQt;VTK::PythonContext2D;VTK::RenderingVolumeOpenGL2;VTK::RenderingOpenGL2;VTK::glew;VTK::opengl;VTK::PythonInterpreter;VTK::Python;VTK::RenderingLabel;VTK::octree;VTK::RenderingLOD;VTK::RenderingImage;VTK::RenderingContextOpenGL2;VTK::IOVeraOut;VTK::hdf5;VTK::IOTecplotTable;VTK::IOSegY;VTK::IOParallelXML;VTK::IOPLY;VTK::IOOggTheora;VTK::theora;VTK::ogg;VTK::IONetCDF;VTK::netcdf;VTK::IOMotionFX;VTK::pegtl;VTK::IOParallel;VTK::jsoncpp;VTK::IOMINC;VTK::IOLSDyna;VTK::IOInfovis;VTK::libxml2;VTK::zlib;VTK::IOImport;VTK::IOGeometry;VTK::IOVideo;VTK::IOMovie;VTK::IOExportPDF;VTK::libharu;VTK::IOExportGL2PS;VTK::RenderingGL2PSOpenGL2;VTK::gl2ps;VTK::png;VTK::IOExport;VTK::RenderingVtkJS;VTK::RenderingSceneGraph;VTK::IOExodus;VTK::exodusII;VTK::IOEnSight;VTK::IOCityGML;VTK::pugixml;VTK::IOAsynchronous;VTK::IOAMR;VTK::InteractionImage;VTK::ImagingStencil;VTK::ImagingStatistics;VTK::ImagingMorphological;VTK::ImagingMath;VTK::GUISupportQtSQL;VTK::IOSQL;VTK::sqlite;VTK::GUISupportQt;VTK::GeovisCore;VTK::libproj;VTK::InfovisLayout;VTK::ViewsCore;VTK::InteractionWidgets;VTK::RenderingVolume;VTK::RenderingAnnotation;VTK::ImagingHybrid;VTK::ImagingColor;VTK::InteractionStyle;VTK::FiltersTopology;VTK::FiltersSelection;VTK::FiltersSMP;VTK::FiltersPython;VTK::FiltersProgrammable;VTK::FiltersPoints;VTK::FiltersVerdict;VTK::verdict;VTK::FiltersParallelImaging;VTK::FiltersImaging;VTK::ImagingGeneral;VTK::FiltersHyperTree;VTK::FiltersGeneric;VTK::FiltersFlowPaths;VTK::FiltersAMR;VTK::FiltersParallel;VTK::FiltersTexture;VTK::FiltersModeling;VTK::FiltersHybrid;VTK::RenderingUI;VTK::DomainsChemistry;VTK::CommonPython;VTK::WrappingPythonCore;VTK::ChartsCore;VTK::InfovisCore;VTK::FiltersExtraction;VTK::ParallelDIY;VTK::diy2;VTK::IOXML;VTK::IOXMLParser;VTK::expat;VTK::ParallelCore;VTK::IOLegacy;VTK::IOCore;VTK::doubleconversion;VTK::lz4;VTK::lzma;VTK::utf8;VTK::FiltersStatistics;VTK::eigen;VTK::ImagingFourier;VTK::ImagingSources;VTK::IOImage;VTK::DICOMParser;VTK::jpeg;VTK::metaio;VTK::tiff;VTK::RenderingContext2D;VTK::RenderingFreeType;VTK::freetype;VTK::kwiml;VTK::RenderingCore;VTK::FiltersSources;VTK::ImagingCore;VTK::FiltersGeometry;VTK::FiltersGeneral;VTK::CommonComputationalGeometry;VTK::FiltersCore;VTK::CommonExecutionModel;VTK::CommonDataModel;VTK::CommonSystem;VTK::CommonMisc;VTK::CommonTransforms;VTK::CommonMath;VTK::CommonCore
find_package(VTK) no longer sets VTK_INCLUDE_DIRS variable. If you look into description part of vtk-config.cmake (script CMake/vtk-config.cmake.in contains template of that file), then you find no note about VTK_INCLUDE_DIRS.
Since VTK_LIBRARIES variable contains IMPORTED targets (in form of VTK::foo), linking with the content of that variable using target_link_libraries will automatically provide include directories.

undefined reference to `zgesvd_' - BLAS issues in C compilation

I am having an issue with the LAPACK/BLAS libraries when compiling a C code that needs them.
The issues are, when I run "make", I get:
file.c:(.text+0x1c41): undefined reference to `zgesvd_'
file.c:(.text+0x1c9c): undefined reference to `zgetrf_'
../file.a(SpatialOrientation.o): In function `myfunction.c':myfunction.c:(.text+0x7be): undefined reference to `dsyev_'
And several other such lines, all referring to similar missing references.
I have chased this error down to being something to do with BLAS. I followed the directions given at this excellent link for installing BLAS and put the relevant directory on the path. I also changed my Makefile accordingly to find these libraries.
Any help on this issue would be really appreciated!
Just to update, I recently installed itpp as well, also following the instructional here, since it seemed my missing references were linked to that. No changes so far...
Thanks for your help!
The problem is solved! Hooray! I just danced around my office...
For those who have the same problem, here is what I did:
1) Follow the instructions given here to make the lapack and blas libraries. To paraphrase, for a scientific Linux 6 machine, they are:
wget http://www.netlib.org/lapack/lapack.tgz
tar xvzf lapack.tgz
cd lapack-3.3.0 //if version number changes, change here to the right directory
mv make.inc.example make.inc
2) Then (important bit, also recommended here):
edit make.inc and add -m64 -fPIC flag to fortran compiler options: FORTRAN, OPTS, NOOPT, LOADER
Then
make blaslib
make
Now, what you have is, in /lapack-3.6.1 (or whatever your directory is called after this process), two files:
librefblas.a , and liblapack.a.
3) The next thing I did was to copy librefblas.a and liblapack.a into some subdirectories - i.e. /lib/liblapack for liblapack.a and /lib/libblas for librefblas.a
4) Then, put those directories in your makefile, like this:
LIBDIR1 = /path/lib/lapack
LIBDIR2 = /path/lib/blas
LIBS = -L$(LIBDIR1) -llapack -L$(LIBDIR2) -lblas $(SYSLIBS)
LIBSMPI = -L$(LIBDIR1) -llapack -L$(LIBDIR2) -lblas $(MPILIBS) $(SYSLIBS)
I also added /path/lib/lapack and /path/lib/blas onto my LD_LIBRARY_PATH (and PATH, just-in-case...)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/lib/lapack:/path/lib/blas
export PATH=$PATH:/path/lib/lapack:/path/lib/blas
Then, go to wherever you Makefile is, and type
make
Yay yay yay!
By the way, with the latest version of lapack and blas, obtained in step 1), I compiled with gcc version 5.1.0 and the corresponding mpicc (openmpi 1.10.2).
Hope this helps someone else and shares the absolute delight.

CMake: collecting libraries

I am using CMake to build a simple C++ project, hereafter named P. The structure of P is quite simple:
P/src/
P/src/package1
P/src/packege2
P/src/...
P/src/main-app
I would like to collect the libraries in package1, package2, ... in a variable called P_LIBS.
In a first attempt, I tried to collect the libraries available in package1, package2, ... in the variable called P_LIBS initially set in the src/CMakeLists.txt file. However, the updates to P_LIBS made in the CMakeLists.txt of the subfolders are not propagated to the parent folder.
I would rather not write a list of libraries in the main CMakeLists.txt file. I would rather modify such variable while moving in the directory tree.
After a search on the internet I could not find any valid suggestion. If I look at the various Find files, I only see long listings of libraries in their main CMakeLists.txt file.
Is there a way to do what (I hope) I explained above?
Thanks to sakra's link I was able to 'propagate' names up to the parent folder. However, the names I add to the P_LIBS variable are later interpreted as 'library' names, not as reference to CMake targets. In other words, if
P_LIBS = {a, b}
the 'a' and 'b' are interpreted as the library names, i.e. CMake generates:
gcc [...] -l a -o exe
instead of
gcc [...] /path/to/a.o -o exe
(.o or other extensions)
You are propably constructing the targets list as a string, try to make them a list instead. For example:
# in package1/CMakeLists.txt
set(P_LIBS ${P_LIBS} a b PARENT_SCOPE)

Linking with libpng & zlib?

I'm trying to compile a project that uses both libjpeg and libpng. I know that libpng needs zlib, so I compiled all the three independently and put them (libjpeg.a, libpng.a and libz.a) on a folder called linrel32. What I execute then is:
g++ -Llinrel32/ program.cpp otherfile.cpp -o linrel32/executable -Izlib/ -Ilpng140/ -Ijpeg/ -lpthread -lX11 -O2 -DLINUX -s -lz -lpng -ljpeg
So I include the three libraries. Still, the linker complains:
linrel32//libpng.a(png.o): In function `png_calculate_crc':
png.c:(.text+0x97d): undefined reference to `crc32'
linrel32//libpng.a(png.o): In function `png_reset_crc':
png.c:(.text+0x9be): undefined reference to `crc32'
linrel32//libpng.a(png.o): In function `png_reset_zstream':
png.c:(.text+0x537): undefined reference to `inflateReset'
linrel32//libpng.a(pngread.o): In function `png_read_destroy':
pngread.c:(.text+0x6f4): undefined reference to `inflateEnd'
linrel32//libpng.a(pngread.o): In function `png_read_row':
pngread.c:(.text+0x1267): undefined reference to `inflate'
linrel32//libpng.a(pngread.o): In function `png_create_read_struct_2':
(... you get the idea :D)
collect2: ld returned 1 exit status
I know the missing functions are from zlib, and I'm adding zlib there. Opened libz.a and it seems to have a good structure. Recompiled it, everything looks fine. But it is not...
I don't know, is likely that the problem is trivial, and what I need is to sleep for a while. But still, if you could help me to figure out this thing ...
You need to rearrange the order of the libraries:
-lpng -ljpeg -lz
What is happening is that the linker has special rules on how it treats static libraries. What it does is that it only includes a .o from inside the .a if the .o is needed to satisfy a reference.
Furthermore, it handles static archives in the order in which they appear on the link line.
So, your code does not directly call any functions in zlib. So when the linker handles -lz first, there are not yet any calls to it so it doesn't pull in any of zlib.
Next, when the linker handles libpng, it sees that there are calls to it from your code. So it pulls the code from libpng and since it makes calls to zlib, now there are references to the zlib functions.
Now you come to the end of your libraries and there are unsatisfied calls which causes your error.
So, if libhigh.a makes use of liblow.a, you must have -lhigh before -llow in your link order.
you probably need to surround the zlib and png headers with extern "C", e.g.:
extern "C" {
#include <zlib.h>
}