How to pre-build a library in CMake - c++

I have been learning CMake and am having persistent build issues with the library Catch2.
I am using Qt as my IDE and have downlaoded Qt6 and MinGW 8 via the Qt maintainance tool.
My issue seems to be that during compilation my test/main.cpp, which includes Catch2, is bloating to the point where the compiler errors.
14:57:22: Running steps for project CMakeTestbed...
14:57:22: Starting: "<dir>\CMake\bin\cmake.exe" --build . --target all
[0/1 ?/sec] Re-running CMake...
-- Could NOT find Vulkan (missing: Vulkan_INCLUDE_DIR)
-- Using the single-header code from <dir>/build-CMakeTestbed-Desktop_Qt_6_0_0_MinGW_64_bit-Debug/_deps/json-src/single_include/
-- Version: 7.1.3
-- Build type: Debug
-- CXX_STANDARD: 17
-- Required features: cxx_variadic_templates
-- Configuring done
-- Generating done
-- Build files have been written to: <dir>/build-CMakeTestbed-Desktop_Qt_6_0_0_MinGW_64_bit-Debug
[1/17 3.7/sec] Automatic MOC and UIC for target fmt
[2/15 5.6/sec] Automatic MOC and UIC for target Catch2WithMain
[3/14 6.8/sec] Automatic MOC and UIC for target CMakeTestbedLib
[4/12 3.6/sec] Automatic MOC and UIC for target CMakeTestbed
[5/10 4.5/sec] Automatic MOC and UIC for target Tests
[6/9 0.4/sec] Building CXX object _deps/catch2-build/CMakeFiles/Catch2WithMain.dir/src/catch_with_main.cpp.obj
FAILED: _deps/catch2-build/CMakeFiles/Catch2WithMain.dir/src/catch_with_main.cpp.obj
C:\Qt\Tools\mingw810_64\bin\g++.exe -I_deps/catch2-build -I_deps/catch2-src -I_deps/catch2-build/Catch2WithMain_autogen/include -I_deps/json-src/include -I_deps/fmt-src/include -I_deps/catch2-src/single_include -g -std=gnu++17 -MD -MT _deps/catch2-build/CMakeFiles/Catch2WithMain.dir/src/catch_with_main.cpp.obj -MF _deps\catch2-build\CMakeFiles\Catch2WithMain.dir\src\catch_with_main.cpp.obj.d -o _deps/catch2-build/CMakeFiles/Catch2WithMain.dir/src/catch_with_main.cpp.obj -c _deps/catch2-src/src/catch_with_main.cpp
C:/Qt/Tools/mingw810_64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe: _deps/catch2-build/CMakeFiles/Catch2WithMain.dir/src/catch_with_main.cpp.obj: too many sections (32805)
<dir>\AppData\Local\Temp\ccE30B5r.s: Assembler messages:
<dir>\AppData\Local\Temp\ccE30B5r.s: Fatal error: can't write 233 bytes to section .text of _deps/catch2-build/CMakeFiles/Catch2WithMain.dir/src/catch_with_main.cpp.obj: 'File too big'
C:/Qt/Tools/mingw810_64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe: _deps/catch2-build/CMakeFiles/Catch2WithMain.dir/src/catch_with_main.cpp.obj: too many sections (32805)
<dir>\AppData\Local\Temp\ccE30B5r.s: Fatal error: can't close _deps/catch2-build/CMakeFiles/Catch2WithMain.dir/src/catch_with_main.cpp.obj: File too big
[7/9 0.4/sec] Building CXX object test/CMakeFiles/Tests.dir/main.cpp.obj
FAILED: test/CMakeFiles/Tests.dir/main.cpp.obj
C:\Qt\Tools\mingw810_64\bin\g++.exe -DFMT_LOCALE -DJSON_USE_IMPLICIT_CONVERSIONS=1 -Itest -I"<dir>/CMakeTestbed/test" -Itest/Tests_autogen/include -I_deps/json-src/include -I_deps/fmt-src/include -I_deps/catch2-src/single_include -I"<dir>/CMakeTestbed/test/../libs" -I"<dir>/CMakeTestbed/test/../src" -I_deps/json-src/single_include -g -std=gnu++17 -MD -MT test/CMakeFiles/Tests.dir/main.cpp.obj -MF test\CMakeFiles\Tests.dir\main.cpp.obj.d -o test/CMakeFiles/Tests.dir/main.cpp.obj -c "<dir>/CMakeTestbed/test/main.cpp"
C:/Qt/Tools/mingw810_64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe: test/CMakeFiles/Tests.dir/main.cpp.obj: too many sections (32805)
<dir>\AppData\Local\Temp\ccARyb79.s: Assembler messages:
<dir>\AppData\Local\Temp\ccARyb79.s: Fatal error: can't write 233 bytes to section .text of test/CMakeFiles/Tests.dir/main.cpp.obj: 'File too big'
C:/Qt/Tools/mingw810_64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe: test/CMakeFiles/Tests.dir/main.cpp.obj: too many sections (32805)
<dir>\AppData\Local\Temp\ccARyb79.s: Fatal error: can't close test/CMakeFiles/Tests.dir/main.cpp.obj: File too big
ninja: build stopped: subcommand failed.
14:57:49: The process "C:\Program Files\CMake\bin\cmake.exe" exited with code 1.
Error while building/deploying project CMakeTestbed (kit: Desktop Qt 6.0.0 MinGW 64-bit)
When executing step "Build"
These issues only occur in debug builds, so I believe the combination of heavy templating, along with the debug symbols is hitting some MinGW compiler threshold...
I am trying something like
target_compile_options(Tests
-Wa
-mbig-obj
)
(Doesn't seem to actually be valid CMake, tried without the '-' too, regardless, this doesn't fix the problem, just hides it...)
But it seems to me the best option would be to make the library precompile in release (I don't need to debug the Catch2 internals, if I am debugging, it is because I have a broken test that I am investigating, and I shouldn't need the dirty details of the lib internals to do that right?)
I have a minimal working example here https://github.com/SebastianTroy/CMakeTestbed.
The main files of interest here would be:
catch2.cmake (from https://github.com/catchorg/Catch2/blob/v2.x/docs/cmake-integration.md#cmake-target)
test/CMakeLists.txt (includes Catch2)
test/main.cpp (the unit that is failing to compile)
I would really appreciate some help with either forcing CMake to precompile the library with higher optimisation flags than the target (to prevent the issue altogether) I would settle for help telling the compiler to ignore the overly large file (to just sidestep the issue)

Related

How should I setup script-based source generation with CMake?

I'm managing the build of a certain C++ repository using CMake. In this repository, and among other things, I have a bunch of .hpp files in a directory, and for each of these, I need to compile a generated bit of source code, which depends on its contents.
Naively, I would do this by generating a correspond .cpp file, and include that file in the source files of the CMake target for the library or executable I'm building. Now, since I don't actually need the source files themselves, I could theoretically just arrange for the compiler to get its source from the command-line instead.
My question: How would I set up this source generation and compilation, using CMake as idiomatically as possible?
Notes:
Assume I have, say, a bash script which can read the .hpp and generate the .cpp on the standard output.
CMake version 3.24 or whichever you like.
Should work on Unix-like operating systems, and hopefully on Windows-like OSes other than the fact that the bash script will fail.
Please comment if additional information is necessary to answer my question.
Let's assume for the sake of portability that you have a Python script, rather than a bash script that manages your code generation. Let's say that it takes two arguments: the source .hpp file and the destination .cpp file. We'll assume it is in your source tree under ./tools/codegen.py.
Now let's assume that your .hpp files are in ./src/genmod for "generated module" because the sources for these headers are generated by codegen.py.
Finally, we'll assume there's a final executable target, app, with a single source file, ./src/main.cpp.
Here's a minimal build that will work for this, with some step-by-step discussion.
We start with some boring boilerplate.
cmake_minimum_required(VERSION 3.24)
project(example)
This probably works on earlier versions, I just haven't tested it, so YMMV. Now we'll create the executable target and link it to our generated sources preemptively. Note that the dependent target does not need to exist before calling target_link_libraries.
add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE genmod)
Now we'll find a Python interpreter and write down an absolute path to the codegen tool.
find_package(Python3 REQUIRED)
set(codegen_py "${CMAKE_CURRENT_SOURCE_DIR}/tools/codegen.py")
Next we'll construct the list of input headers. I'm imagining there are three: A.hpp, B.hpp, and C.hpp.
set(input_headers A.hpp B.hpp C.hpp)
list(TRANSFORM input_headers PREPEND src/genmod/)
I used list(TRANSFORM) here to save some typing. Now we'll just create an object library called genmod, which will "hold" the objects for the generated C++ files.
add_library(genmod OBJECT)
And now comes the real meat. For each of the headers, ...
foreach (header IN LISTS input_headers)
we'll construct absolute paths to the header and generated source files ...
string(REGEX REPLACE "\\.hpp$" ".cpp" gensrc "${header}")
set(header "${CMAKE_CURRENT_SOURCE_DIR}/${header}")
set(gensrc "${CMAKE_CURRENT_BINARY_DIR}/${gensrc}")
and then write a custom command that knows how to call codegen.py. We specify the outputs, command arguments, and dependencies. Don't forget to include the generator script as a dependency, and never forget to pass VERBATIM to ensure consistent, cross-platform, argument quoting.
add_custom_command(
OUTPUT "${gensrc}"
COMMAND Python3::Interpreter "${codegen_py}" "${header}" "${gensrc}"
DEPENDS "${header}" "${codegen_py}"
VERBATIM
)
Finally, we attach this source to genmod.
target_sources(genmod PRIVATE "${gensrc}")
endforeach ()
We can test this build using Ninja's dry-run feature to make sure the commands look correct.
$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Python3: /home/reinking/.venv/default/bin/python3.9 (found version "3.9.2") found components: Interpreter
-- Configuring done
-- Generating done
-- Build files have been written to: /home/reinking/test/build
$ cmake --build build -- -nv
[1/8] cd /home/reinking/test/build && /home/reinking/.venv/default/bin/python3.9 /home/reinking/test/tools/codegen.py /home/reinking/test/src/genmod/A.hpp /home/reinking/test/build/src/genmod/A.cpp
[2/8] cd /home/reinking/test/build && /home/reinking/.venv/default/bin/python3.9 /home/reinking/test/tools/codegen.py /home/reinking/test/src/genmod/B.hpp /home/reinking/test/build/src/genmod/B.cpp
[3/8] cd /home/reinking/test/build && /home/reinking/.venv/default/bin/python3.9 /home/reinking/test/tools/codegen.py /home/reinking/test/src/genmod/C.hpp /home/reinking/test/build/src/genmod/C.cpp
[4/8] /usr/bin/c++ -O3 -DNDEBUG -MD -MT CMakeFiles/genmod.dir/src/genmod/A.cpp.o -MF CMakeFiles/genmod.dir/src/genmod/A.cpp.o.d -o CMakeFiles/genmod.dir/src/genmod/A.cpp.o -c /home/reinking/test/build/src/genmod/A.cpp
[5/8] /usr/bin/c++ -O3 -DNDEBUG -MD -MT CMakeFiles/genmod.dir/src/genmod/B.cpp.o -MF CMakeFiles/genmod.dir/src/genmod/B.cpp.o.d -o CMakeFiles/genmod.dir/src/genmod/B.cpp.o -c /home/reinking/test/build/src/genmod/B.cpp
[6/8] /usr/bin/c++ -O3 -DNDEBUG -MD -MT CMakeFiles/genmod.dir/src/genmod/C.cpp.o -MF CMakeFiles/genmod.dir/src/genmod/C.cpp.o.d -o CMakeFiles/genmod.dir/src/genmod/C.cpp.o -c /home/reinking/test/build/src/genmod/C.cpp
[7/8] /usr/bin/c++ -O3 -DNDEBUG -MD -MT CMakeFiles/app.dir/src/main.cpp.o -MF CMakeFiles/app.dir/src/main.cpp.o.d -o CMakeFiles/app.dir/src/main.cpp.o -c /home/reinking/test/src/main.cpp
[8/8] : && /usr/bin/c++ -O3 -DNDEBUG CMakeFiles/genmod.dir/src/genmod/A.cpp.o CMakeFiles/genmod.dir/src/genmod/B.cpp.o CMakeFiles/genmod.dir/src/genmod/C.cpp.o CMakeFiles/app.dir/src/main.cpp.o -o app && :
And indeed we can see that the commands are what we'd naturally expect them to be.

QT5 and Antlr4.8 not Compiling with Cmake and QT Creator

As in the above im trying to compile a QT5 project inside of QT Creator with cmake and want to add the antlr package.
Infos: Qt 5.12.8, Antlr 4.8, Compilers tried: mingw gcc|g++ , msvc 2015,2017
System: Windows / Linux both do not work
For including Antlr 4.8 i use the provided CPP Package to build Antlr from Source
This is the project i am working on.
https://github.com/MrDiver/ArmSimulator/tree/ArmParser/src/asmeditor/AsmEditor
i include antlr4 with the following https://github.com/MrDiver/ArmSimulator/blob/ArmParser/src/asmeditor/AsmEditor/CMakeLists.txt#L14-L21
and normally it works perfectly fine when i compile something with it. But this time when i try to include the header files for antlr i get this error message
FAILED: CMakeFiles/AsmEditor.dir/managers/processormanager.cpp.obj
H:\Programme\QT\Tools\mingw730_64\bin\g++.exe -DANTLR4CPP_STATIC -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_WIDGETS_LIB -I. -IH:/MyStuff/PrivateProjects/CPPProjects/ArmSimulator/src/asmeditor/AsmEditor -IAsmEditor_autogen/include -Iantlr4_runtime/src/antlr4_runtime/runtime/Cpp/runtime/src -IH:/MyStuff/PrivateProjects/CPPProjects/ArmSimulator/src/asmeditor/AsmEditor/armparser/assembler -IH:/MyStuff/PrivateProjects/CPPProjects/ArmSimulator/src/asmeditor/AsmEditor/armparser/walker -IH:/MyStuff/PrivateProjects/CPPProjects/ArmSimulator/src/asmeditor/AsmEditor/codearea -IH:/MyStuff/PrivateProjects/CPPProjects/ArmSimulator/src/asmeditor/AsmEditor/managers -IH:/MyStuff/PrivateProjects/CPPProjects/ArmSimulator/src/asmeditor/AsmEditor/armparser -isystem H:/Programme/QT/5.12.8/mingw73_64/include -isystem H:/Programme/QT/5.12.8/mingw73_64/include/QtWidgets -isystem H:/Programme/QT/5.12.8/mingw73_64/include/QtGui -isystem H:/Programme/QT/5.12.8/mingw73_64/include/QtANGLE -isystem H:/Programme/QT/5.12.8/mingw73_64/include/QtCore -isystem H:/Programme/QT/5.12.8/mingw73_64/./mkspecs/win32-g++ -O3 -DNDEBUG -std=gnu++11 -MD -MT CMakeFiles/AsmEditor.dir/managers/processormanager.cpp.obj -MF CMakeFiles\AsmEditor.dir\managers\processormanager.cpp.obj.d -o CMakeFiles/AsmEditor.dir/managers/processormanager.cpp.obj -c H:/MyStuff/PrivateProjects/CPPProjects/ArmSimulator/src/asmeditor/AsmEditor/managers/processormanager.cpp
In file included from antlr4_runtime/src/antlr4_runtime/runtime/Cpp/runtime/src/antlr4-runtime.h:31:0,
from H:/MyStuff/PrivateProjects/CPPProjects/ArmSimulator/src/asmeditor/AsmEditor/managers/processormanager.cpp:2:
antlr4_runtime/src/antlr4_runtime/runtime/Cpp/runtime/src/Lexer.h:116:46: error: invalid declarator before 'newToken'
virtual void emit(std::unique_ptr<Token> newToken);
^~~~~~~~
antlr4_runtime/src/antlr4_runtime/runtime/Cpp/runtime/src/Lexer.h:116:46: error: expected ')' before 'newToken'
antlr4_runtime/src/antlr4_runtime/runtime/Cpp/runtime/src/Lexer.h:123:25: error: expected unqualified-id before ')' token
virtual Token* emit();
^
[30/31 0.6/sec] Building CXX object CMakeFiles/AsmEditor.dir/armparser/assembler/ARMParser.cpp.obj
ninja: build stopped: subcommand failed.
18:59:55: The process "C:\msys64\mingw64\bin\cmake.exe" exited with code 1.
Error while building/deploying project AsmEditor (kit: Desktop Qt 5.12.8 MinGW 64-bit)
When executing step "CMake Build"
File of Interest: https://github.com/MrDiver/ArmSimulator/blob/ArmParser/src/asmeditor/AsmEditor/managers/processormanager.cpp
Seems pretty much like it can't find std::unique_ptr<Token> but i can't change a lot about this, because these are the antlr sources and they actually work.
So i don't really know anymore where to search for the problem. The library itself compiles fine if i choose it as target in the settings.
What i tried:
Compiling the antlr library outside and just linking it in the cmake file.
Changing the Lexer.h file with #include <memory>.
Compiling the QT project without QT Creator (Resulting in a ton more errors because i cant get the linking for QT to work)
Compiling every Antlr related file outside of the project (Works perfectly fine without QT but not really what i need)
Using different compilers and different Systems.
Searching for a problem with moc but it doesn't seem to influence it. But i doubt i looked hard enough on moc for this.
And im quite new to QT so i don't know everything what the Qt Creator does behind the scenes. It seems like too much if i can't compile it with plain cmake out of the box.
Thanks for the help in advance.
The problem is that Antlr has methods like "emit" that conflict with the Qt reserved word "emit". The solution is to disable the flag "no_keywords" (in qmake add CONFIG += no_keywords, and in CMake add add_definitions(-DQT_NO_KEYWORDS)) as indicated by the docs. Then you must make the following conversions:
emit to Q_EMIT
slot to Q_SLOT
slots to Q_SLOTS
signal to Q_SIGNAL
signals to Q_SIGNALS

Eclipse: Edit toolchain (remove build step to create a shared library for CUDA)

I am trying to configure Eclipse such that it compiles a shared library in one project and uses it in another.
The problem is, that using the CUDA plugin for Eclipse one can only choose an executable generating project type.
So what I want to do is creating such a project and modify that toolchain such that Eclipse does not execute anything else than nvcc.
As you can see compiling the library is not a problem:
18:27:25 **** Incremental Build of configuration Default for project cudamath ****
make all
Building file: ../test.cu
Invoking: CUDA NVCC Compiler
nvcc --shared -Xcompiler -fPIC -o "cu_test.o" "../test.cu" && \
echo -n 'cu_test.d' ./ > 'cu_test.d' && \
nvcc -M "../test.cu" >> 'cu_test.d'
nvcc warning : The 'compute_10' and 'sm_10' architectures are deprecated, and may be removed in a future release.
nvcc warning : The 'compute_10' and 'sm_10' architectures are deprecated, and may be removed in a future release.
Finished building: ../test.cu
The problem is that Eclipse then calls g++ which is that step of the toolchain I want to cut off:
Building target: cudamath
Invoking: C++ Linker
g++ -L/opt/cuda/lib64 -o "cudamath" ./cu_test.o -lcuda -lcublas -lcudart
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../lib/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
makefile:32: recipe for target 'cudamath' failed
make: *** [cudamath] Error 1
Is there a way I can do this? I've been crawling through my project settings but I can't seem to find what I'm looking for.
Here's what I did using Nsight Eclipse Edition:
File... new CUDA C/C++ project
In the next dialog, select Shared Library...Empty Project, and give the project a name (let's say it is testlib)
Finish that wizard/dialog. A new testlib project is created in the project explorer on the left
In the project explorer on the left, right click on the project name and create a new folder for your source files
Open that folder and create your new source file. For this, I selected a CUDA C/C++ source file using the CUDA bitreverse "template". This creates a new source file with the bitreverse code in it.
change int main() { in your source file to int myfunc(){
save the source file and build the project. A new libtestlib.so is successfully built.

Error 255 when try to create .exe using dev-C++

Today i got the most generic compile error for Dev-C++ ever
Compiler: Default compiler
Building Makefile: "C:\projects\Makefile.win"
Executing make...
make.exe -f "C:\projects\Makefile.win" all
g++.exe -c test.cpp -o test.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include" -I"C:/SDL-1.2.15/include"
make.exe: *** [test.o] Error 255
Execution terminated
and that's it. I googled around online but usually you can see some other type of errors follow it within the compile log but no in my case. Anyone help. I am running this on window 8
Please update your IDE to the following version, which fixes an immense list of bugs, ships with GCC 4.6.1 or 4.7.0, and is fully portable: http://sourceforge.net/projects/orwelldevcpp/
That would be the number one fix to try and fix this problem regarding the automatically generated makefile. Chances are the updated version will fix your makefile problems.
You could also open up the auto generated makefile yourself and:
Go to Project >> Project Options >> Makefile and tick "use custom makefile".
Try to fix the makefile manually.
???
Rebuild.
Profit.
If this option was previously left unticked, you are sure either the old Dev-C++ made an error creating the makefile or the bundled compiler got broken for some reason.

eclipse CDT: rebuilding a dependent project

I'm working on a C++ project with eclipse Indigo + CDT running on linux
It's made of a project for a library, and a project with unit tests for this library.
Obviously the second project depends on the first one.
Both projects use the external builder
But when I modify a header of the first project it does not rebuild the test project. And I can't make it do it... It'll just re-link the second project, even though the header is included in the test project. This is very annoying because I often have working builds while working on the library, then at some point I do a full rebuild and I see a load of errors, on stuff I did 30 minutes ago!
example output of the CDT Global Build Console:
**** Build of configuration Debug for project libxxx ****
make -j all
Building file: ../foo.cpp
Invoking: GCC C++ Compiler
ccache g++ -I"/home/foke/workspaces/cpp/libxxx/include" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"foo.d" -MT"foo.d" -o "foo.o" "../foo.cpp"
Finished building: ../foo.cpp
Building target: libxxx.a
Invoking: GCC Archiver
ar -r "libxxx.a" ./foo.o ./src/yyy.o ./src/detail/zzz.o
ar: creating libxxx.a
Finished building target: libxxx.a
**** Build Finished ****
**** Build of configuration Debug for project libxxx_tests ****
make -k -j all
Building target: libxxx_tests
Invoking: Cross G++ Linker
g++ -L"/home/foke/workspaces/cpp/libxxx/Debug" -o "libxxx_tests" ./main.o ./aaa.o ./tests/bbb.o ./tests/ccc.o ./tests/ddd.o -lboost_unit_test_framework -lxxx
Finished building target: libxxx_tests
**** Build Finished ****
If you're used to the latest versions of MS Visual Studio then you should clear off a space on your desk and mark it with a giant 'X' - this enevitably where your fist and maybe even your head will bang in frustration when using eclipse/CDT.
Eclipse has it's own dependency mechanism which does almost nothing, but fortunately the CDT module has its own dependency mechanism which tries to do what you want. To set up project dependencies go to:
Project-->Properties-->C/C++ General-->Paths and Symbols-->References
So in your example you would go to the project properties for "libxxx_tests" and select "libxxx.a" as a dependency.
Note that you can also use this page to set the library order, which may be an important step depending on the complexity of your project.