Trouble linking .a libraries in c++ using tutorial as guide

Hi, I’m using cmake version 3.28.3, working with the tutorial on the cmake website, and got through Step 1 Exercise 3. Using that, I tried to link a library like so:


cmake_minimum_required(VERSION 3.28)

project(ES3)

add_executable(ES3Main)

target_sources(ES3Main
PRIVATE
game.cpp
)

target_link_libraries(ES3Main PRIVATE raylib)

add_library(raylib)

target_sources(raylib
PRIVATE
raylib/libraylib.a

PUBLIC
    FILE_SET HEADERS
    BASE_DIRS
        raylib
    FILES
        raylib/raylib.h

)

But I get

CMake Error: Cannot determine link language for target “raylib”.
CMake Error: CMake can not determine linker language for target: raylib
– Generating done (0.0s)
CMake Generate step failed. Build files cannot be regenerated correctly.
gmake: *** [Makefile:193: cmake_check_build_system] Error 1

The only difference I can think of between what the tutorial does and what I’m doing is that I’m using a file with a “.a” extension. Honestly it’s my first time coming across that extension since I’m just getting back to c++ after about a decade. Note that I can run examples, and I definitely have g++ installed, and doing the tutorial with a .cxx file worked just fine.

What am I doing wrong? Is there a name for these “.a” files I should be searching for? Is this something that the tutorial will get to eventually, or is there some dependency I’m missing? I’m on Ubuntu 24

Valid extensions for c++ are:

"sourceFileExtensions": [
        "C", "M", "c++", "cc", "cpp", "cxx", "mm", "CPP"
]

Why do you want to use „.a“?

You want to create an imported target for the raylib, but you’re creating a normal target instead.

You have like 3 options to do it right:

It’s just what came out when I downloaded raylib and ran cmake for it according to the instructions.

Thank you!

I don’t really understand the difference between an imported target and a normal target… It sounds like an imported target is something “already built”? Honestly I’m not even really sure what a “.a” file is.

Since you’re on linux, the “.a” is simply a static library - in this case the compiled raylib.

Your intuition regarding the target types is right. Normal targets are the things that you build from source. Imported targets are a way to use precompiled stuff in the same as the things you build.

Let’s look at your situation. You probably want something like this:

cmake_minimum_required(VERSION 3.28)

project(ES3)

# import raylib
add_library(raylib::raylib STATIC IMPORTED)
set_target_properties(raylib::raylib PROPERTIES
                      INTERFACE_INCLUDE_DIRECTORIES raylib)
set_target_properties(raylib::raylib PROPERTIES
                      IMPORTED_LOCATION raylib/libraylib.a)


# main executable
add_executable(ES3Main)
target_sources(ES3Main
               PRIVATE
                 game.cpp
)

target_link_libraries(ES3Main PRIVATE raylib::raylib)

Note: because this is a static library, it does not carry any information about dependencies. If you get link errors, you may have to investigate that. From the other hand it may be possible to use find_package instead if you install raylib to a prefix after building it, or you may consider bringing raylib into your build via FetchContent module.

Oooh, ok. This clarifies it. Now that I understand “.a” is a linux concept and not really some code specific concept, it all makes more sense. I think you’re right–it’s probably best to use FetchContent.

Thanks for the thorough and knowledgeable answer!