(cmake beginner) LNK 2019 with all library. what did i do wrong

Hello every one. I’m a beginner in cmake. I try to rebuild a project that i did on QT with qmake but this time with cmake but i have a lot of difficulties to make it work. all libraries in subdirectory return an error ln2019 and i don’t know why.

as i did more or less the same things for all libraries, I will try to be more precise with one of them and correct the others according to your help.

Here the structure of the code for the fit library:

CMakeLists.txt
AstroBase
├── src
 .        ├── CMakeLists.txt
 .        ├── main.cpp
 .        ├── mainwindow.h
 .        ├── mainwindow.cpp
 .        ├── mainwindow.ui
 .        ├──utils
 .         .       ├── CMakeLists.txt
 .         .       └── fit
 .         .        .       ├── CMakeLists.txt
 .         .        .       ├── fit.h
 .         .        .       └── fit.cpp


here root/CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)

project(AstroBase VERSION 0.1 LANGUAGES CXX)

macro(print_all_variables)
    message(STATUS "print_all_variables------------------------------------------{")
    get_cmake_property(_variableNames VARIABLES)
    foreach (_variableName ${_variableNames})
        message(STATUS "${_variableName}=${${_variableName}}")
    endforeach()
    message(STATUS "print_all_variables------------------------------------------}")
endmacro()

function(add_qt6)
  #find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools)
  find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools)
  link_libraries(Qt${QT_VERSION_MAJOR}::Widgets)
endfunction()


set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(FORMS_DIR "${CMAKE_SOURCE_DIR}/AstroBase/forms")
set(INCLUDE_DIR "${CMAKE_SOURCE_DIR}/AstroBase/include")
set(SOURCE_DIR "${CMAKE_SOURCE_DIR}/AstroBase/src")
set(TS_DIR "${CMAKE_SOURCE_DIR}/AstroBase/TS")

set(CFITSIO_INCLUDE_DIR_X86 "C:/vcpkg/vcpkg/packages/cfitsio_x86-windows/include/")
set(CFITSIO_INCLUDE_DIR_X64 "C:/vcpkg/vcpkg/packages/cfitsio_x64-windows/include/")

set(CFITSIO_LIB_DIR_X86 "C:/vcpkg/vcpkg/packages/cfitsio_x86-windows/lib")
set(CFITSIO_LIB_DIR_X64 "C:/vcpkg/vcpkg/packages/cfitsio_x86-windows/lib")

#include("C:/opencv/opencv/sources/cmake/FindOpenCV.cmake")
set(OpenCV_DIR "C:/opencv/opencv/build")

find_package( OpenCV REQUIRED )

include_directories(${OpenCV_INCLUDE_DIRS})


include_directories(${FORMS_DIR})
include_directories(${INCLUDE_DIR})
include_directories(${SOURCE_DIR})
include_directories(${TS_DIR})

#file(GLOB_RECURSE SOURCES
#    "${FORMS_DIR}/*.ui"
#    "${FORMS_DIR}/*.qrc"
#    "${INCLUDE_DIR}/*.h"
#    "${SOURCE_DIR}/*.cpp"
#    "${TS_DIR}/*.ts")

set(PROJECT_SOURCES
     ${SOURCE_DIR}/main.cpp
     ${SOURCE_DIR}/mainwindow.cpp
     ${SOURCE_DIR}/mainwindow.h
     ${SOURCE_DIR}/mainwindow.ui
)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools)

set(TS_FILES "${TS_DIR}/AstroBase_fr_FR.ts")



if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)

    qt_add_executable(AstroBase
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
    )
   

# Define target properties for Android with Qt 6 as:
#    set_property(TARGET AstroBase APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
#                 ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation

    qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})

else()
    if(ANDROID)
        add_library(AstroBase SHARED
            ${PROJECT_SOURCES}
        )
# Define properties for Android with Qt 5 after find_package() calls as:
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
    else()
        add_executable(AstroBase
            ${PROJECT_SOURCES}
        )
    endif()

    qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()
     
target_link_libraries(AstroBase PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)


#add_library(opencv_world470 STATIC IMPORTED)
#set_property(TARGET opencv_world470 PROPERTY IMPORTED_IMPLIB "C:/opencv/opencv/build/x64/vc16/lib/opencv_world470.lib")
#target_link_directories(AstroBase PRIVATE "C:/opencv/opencv/build/x64/vc16/lib")

target_link_libraries(AstroBase PRIVATE ${OpenCV_LIBS})

add_subdirectory("./AstroBase/src")


target_include_directories(AstroBase PRIVATE ${CFITSIO_INCLUDE_DIR_X64})
target_link_directories(AstroBase PRIVATE ${CFITSIO_LIB_DIR_X64})
add_library(cfitsio STATIC ${CFITSIO_INCLUDE_DIR_X64}
                            ${CFITSIO_LIB_DIR_X64})


set_target_properties(AstroBase PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

install(TARGETS AstroBase
    BUNDLE DESTINATION .
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

if(QT_VERSION_MAJOR EQUAL 6)
    qt_finalize_executable(AstroBase)
endif()


CMakeLists for ./AstroBase/src:

add_executable(automata ${PROJECT_SOURCES})
add_qt6()


add_subdirectory(widgets)
add_subdirectory(utils)
add_subdirectory(data_struct)

target_link_libraries(automata PUBLIC 
        widgets
        utils 
        dataStruct)

CMakeLists for ./AstroBase/src/utils:

add_library(utils "")

add_subdirectory(fit)

target_link_libraries(utils PRIVATE 
		fit)

CMakeLists for ./AstroBase/src/utils/fit:

add_library(fit fit.cpp)


target_include_directories(fit PRIVATE ${CFITSIO_INCLUDE_DIR_X64})
target_link_directories(fit PRIVATE ${CFITSIO_LIB_DIR_X64})
#add_library(cfitsio STATIC ${CFITSIO_INCLUDE_DIR_X64}
#                            ${CFITSIO_LIB_DIR_X64})


target_sources(fit
  PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/fit.cpp
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}/fit.h
  )

target_include_directories(fit
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}
 )

I know this cmakes can look like little bit dirty but it’s my first cmakes and i tried a lot of things

here the code for fit.cpp

#include "fit.h"
#include <QDebug>

void Fit::open(const char* path , img* Img) {

    int status = 0,nkeys;
    int nullval = 0;
    int anynul = 0;
    fitsfile* fptr;
    char ctmp[80], comment[120];



    fits_open_file(&fptr, path, READONLY, &status); // open file


    fits_get_hdrspace(fptr, &nkeys, NULL, &status);

    //char** header2 = new char*[nkeys];
    Img->header = new arrayS<arrayS<char>>(nkeys);


    //Img->header->size = new long[2];
    for (int ii = 1; ii <= nkeys; ii++)  {
        //header2[ii-1] = new char[FLEN_CARD];
        Img->header->ary = new arrayS<char>(FLEN_CARD);
        fits_read_record(fptr, ii, Img->header->ary->ary, &status);

    }


    /*Img->header->array = header2;
    Img->header->size[0] = nkeys;
    Img->header->size[1] = FLEN_CARD;*/


    fits_read_key(fptr, TSTRING, "BITPIX", ctmp, comment, &status);
    Img->bitEncoding =  std::stoi(ctmp);
    fits_read_key(fptr, TSTRING, "NAXIS", ctmp, comment, &status);
    Img->naxis =  std::stoi(ctmp);

    qDebug() << Img->bitEncoding << " " << Img->naxis;

    fits_get_img_dim(fptr, &Img->dim, &status);	// get dim of image (color or gray scale basicly
    Img->size = new long[Img->dim];

    fits_get_img_size(fptr, 2, Img->size, &status); // get size of image (pixels)
    Img->totalPixels = getTotalPixel(Img->dim, Img->size);
    Img->data = new unsigned short[Img->totalPixels];
    fits_read_img(fptr, USHORT_IMG, 1, Img->totalPixels, &nullval, Img->data, &anynul, &status);
    fits_close_file(fptr, &status);

}

void Fit::save(img *Img)
{
     fitsfile* fptr;
     int status = 0;
     unsigned short **data = (unsigned short **)malloc(Img->size[1] * sizeof(unsigned short *));
     for (int i=0; i<Img->size[1]; i++) {
          data[i] = (unsigned short *)malloc(Img->size[0] * sizeof(unsigned short));
          for(int j = 0; j < Img->size[0]; j++)
              data[i][j] = Img->data[i * Img->size[1] + j];
     }
     long size[2] = {Img->size[0], Img->size[1]};
     fits_create_file(&fptr, Img->path, &status);
     fits_create_img(fptr, SHORT_IMG, Img->naxis, size, &status);
     fits_write_img(fptr, TSHORT, 1, Img->totalPixels, Img->data, &status);
     qDebug() << "save " << Img->path;
     delete data;
}



int Fit::getTotalPixel(int dim, long* size) {
    int multOfAllPixel = 1;
    for (int i = 0; i < dim; i++)
        multOfAllPixel *= size[i];
    return multOfAllPixel;

}

and fit.h

#ifndef FIT_H
#define FIT_H

#include "cfitsio/fitsio.h"
#include "../../data_struct/structurs.h"
#include <vector>
#include <utility>

using namespace std;
class Fit
{

public:

    static  void open(const char* path, img * Img);
    static  void save(img * Img);


private:
    static int getTotalPixel(int dim, long * size);
};



#endif // FIT_H

and also the code of the main.cpp where i did the test:

#include "mainwindow.h"

#include <QApplication>
#include <QLocale>
#include <QTranslator>

#include "./data_struct/structurs.h"
#include "./utils/fit/fit.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QTranslator translator;
    const QStringList uiLanguages = QLocale::system().uiLanguages();
    for (const QString &locale : uiLanguages) {
        const QString baseName = "AstroBase_" + QLocale(locale).name();
        if (translator.load(":/i18n/" + baseName)) {
            a.installTranslator(&translator);
            break;
        }
    }

    img* test = new img();
    string y = "../imtest.fits";
    const char* yolo = y.c_str();
    Fit::open(yolo, test);



 
    MainWindow w;
    w.show();
    return a.exec();
}

the error that i get is this one:

LNK2019	unresolved external symbol "public: static void __cdecl Fit::open(char const *,struct img *)" (?open@Fit@@SAXPEBDPEAUimg@@@Z) refer in function main		

can you explain me what i do wrong in my cmakes pls? that quit a long time that im fighting with this (and others problems that i solved already).

Thank you in advance.

I don’t see target_link_libraries(AstroBase PRIVATE fit) anywhere to give the fit library to AstroBase.

thank you for your reply. i didn’t put target_link_libraries(AstroBase PRIVATE fit) because i put target_link_libraries(utils PRIVATE fit) at./AstroBase/src/utils then target_link_libraries(automata PUBLIC widgets utils dataStruct) at ./AstroBase/src. finaly i put add_subdirectory at root/CMakeLists.txt.

but indeed, i didn’t put target_link_libraries(AstroBase PRIVATE automata).

so, I just did it now and I modify the first line of the CMakeLists ./AstroBase/src from add_executable(automata ${PROJECT_SOURCES}) to add_library(automata “”) and i get a different error:

LNK1181	cannot open input file 'AstroBase\src\widgets\section\section.lib'

section is an other library with this cmake (I will update the dir tree):

add_library(section SHARED section.cpp)
add_qt6()

target_include_directories(section PUBLIC ${CMAKE_CURRENT_LIST_DIR}/section.h)
target_link_directories(section PRIVATE ${CMAKE_CURRENT_LIST_DIR}/section.cpp)

target_sources(section
  PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/section.cpp
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}/section.h
  )
  target_include_directories(section
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}
 )

as you can see this cmake is more or less the same than for fit.

new dir tree:

CMakeLists.txt
AstroBase
├── src
 .        ├── CMakeLists.txt
 .        ├── main.cpp
 .        ├── mainwindow.h
 .        ├── mainwindow.cpp
 .        ├── mainwindow.ui
 .        ├──utils
 .         |       ├── CMakeLists.txt
 .         |       └── fit
 .         |        .       ├── CMakeLists.txt
 .         |        .       ├── fit.h
 .         |        .       └── fit.cpp
 .         ├── widgets
 .         .        ├── CMakeLists.txt
 .         .        └── section
 .         .                ├── CMakeLists.txt
 .         .        .       ├── section.h
 .         .        .       └── section.cpp

with ./ AstroBase/src/widget/cmakelists:

add_library(widgets "")

add_subdirectory(section)

target_link_libraries(widgets PUBLIC 
		section)

On Windows, this tends to be a symptom of not exporting symbols (FOO_EXPORT macros) as the linker won’t output a linkable .lib without any symbols. See the GenerateExportHeader module for the API there to help with the _EXPORT macro wrangling.

sorry for the late of my reply. i’m little bit busy.

i tried what you send to me but the error is still more or less the same:

LNK1104	cannot open file 'AstroBase\src\widgets\section\section.lib'	

I have this error whatever if i add it or not.

my new cmake for section:

add_library(section SHARED section.cpp)
add_qt6()

 
include(GenerateExportHeader)
generate_export_header(section)

target_include_directories(section PUBLIC ${CMAKE_CURRENT_LIST_DIR}/section.h)
target_link_directories(section PRIVATE ${CMAKE_CURRENT_LIST_DIR}/section.cpp)

target_sources(section
  PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/section.cpp
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}/section.h
  )
  target_include_directories(section
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}
 )
include(GenerateExportHeader)
generate_export_header(section)

Finally i understood (more or less) where it’s come from. it was because i set my library as SHARED. now I put it a STATIC and this error gone.

But the pain is not finish and i begin to be little bit crazy.

CMake Error at C:/Program Files/Microsoft Visual Studio/2022/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-3.24/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find ZLIB (missing: ZLIB_LIBRARY ZLIB_INCLUDE_DIR)		C:/Program Files/Microsoft Visual Studio/2022/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-3.24/Modules/FindPackageHandleStandardArgs.cmake	230	

I don’t even use zlib in this project. I installed it for an other project…