Search code examples
c++cmakedcmtk

fatal error: dcmtk/config/osconfig.h: No such file or directory


I am desperately trying, as a CMake newbie to get DCMTK to do stuff. The example I am trying to compile and run is the following:

#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dctk.h"
#include "dcmtk/dcmdata/dcistrmf.h"

int main(int argc, char *argv[])
{
    OFCondition status;

    /* approach 1 */
    DcmMetaInfo metainfo;
    status = metainfo.loadFile("test.dcm");
    if (status.good())
    {
        OFString sopClassUID, xferUID;
        if (metainfo.findAndGetOFString(DCM_MediaStorageSOPClassUID, sopClassUID).good())
            COUT << "SOP Class UID: " << sopClassUID << OFendl;
        if (metainfo.findAndGetOFString(DCM_TransferSyntaxUID, xferUID).good())
            COUT << "Transfer Syntax UID: " << xferUID << OFendl;
        metainfo.print(COUT);
    }

    /* approach 2 */
    DcmFileFormat fileformat;
    status = fileformat.loadFile("test.dcm", EXS_Unknown, EGL_noChange, DCM_MaxReadLength, ERM_metaOnly);
    if (status.good())
    {
        OFString sopClassUID, xferUID;
        if (fileformat.getMetaInfo()->findAndGetOFString(DCM_MediaStorageSOPClassUID, sopClassUID).good())
            COUT << "SOP Class UID: " << sopClassUID << OFendl;
        if (fileformat.getMetaInfo()->findAndGetOFString(DCM_TransferSyntaxUID, xferUID).good())
            COUT << "Transfer Syntax UID: " << xferUID << OFendl;
        fileformat.print(COUT);
    }

    /* approach 3 */
    fileformat.clear();
    DcmInputFileStream fileStream("test.dcm");
    status = fileStream.status();
    if (status.good())
    {
        /* first, read meta-header */
        fileformat.setReadMode(ERM_metaOnly);
        fileformat.transferInit();
        status = fileformat.read(fileStream);
        if (status.good())
        {
            OFString sopClassUID, xferUID;
            if (fileformat.getMetaInfo()->findAndGetOFString(DCM_MediaStorageSOPClassUID, sopClassUID).good())
                COUT << "SOP Class UID: " << sopClassUID << OFendl;
            if (fileformat.getMetaInfo()->findAndGetOFString(DCM_TransferSyntaxUID, xferUID).good())
                COUT << "Transfer Syntax UID: " << xferUID << OFendl;
            /* then read dataset if certain criteria are met */
            if (sopClassUID == UID_SecondaryCaptureImageStorage)
            {
                fileformat.setReadMode(ERM_autoDetect);
                status = fileformat.read(fileStream);
                if (status.good())
                {
                    fileformat.print(COUT);
                }
            }
        }
        fileformat.transferEnd();
    }

    return 0;
}

The problem comes from the upper part of this file. I am aware that as is, in a specific folder, this code will have a building error as it will not find the dcmtk folder in the project directory. I have built and installed DCMTK in different folders somewhere else on my drive. I therefore have two folders: dcmtk-3.6.5-build and dcmtk-3.6.5-install. I know that what I am interested in is in dcmtk-3.6.5-install/include/. But when building I get the following error:

====================[ Build | test_dcmtk | Debug ]==============================
/snap/clion/139/bin/cmake/linux/bin/cmake --build /home/project_dir/test_dcmtk/cmake-build-debug --target test_dcmtk -- -j 38
Scanning dependencies of target test_dcmtk
[ 50%] Building CXX object CMakeFiles/test_dcmtk.dir/main.cpp.o
/home/project_dir/test_dcmtk/main.cpp:1:10: fatal error: dcmtk/config/osconfig.h: No such file or directory
    1 | #include "dcmtk/config/osconfig.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [CMakeFiles/test_dcmtk.dir/build.make:83: CMakeFiles/test_dcmtk.dir/main.cpp.o] Error 1
make[2]: *** [CMakeFiles/Makefile2:96: CMakeFiles/test_dcmtk.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:103: CMakeFiles/test_dcmtk.dir/rule] Error 2
make: *** [Makefile:138: test_dcmtk] Error 2

As I understand it, I should direct the compiler to the directory where DCMTK is installed. However when I do it, I get a very similar error:

====================[ Build | test_dcmtk | Debug ]==============================
/snap/clion/139/bin/cmake/linux/bin/cmake --build /home/project_dir/test_dcmtk/cmake-build-debug --target test_dcmtk -- -j 38
Scanning dependencies of target test_dcmtk
[ 50%] Building CXX object CMakeFiles/test_dcmtk.dir/main.cpp.o
In file included from /home/project_dir/test_dcmtk/main.cpp:2:
/home/dcmtk-3.6.5-install/include/dcmtk/dcmdata/dctk.h:25:10: fatal error: dcmtk/config/osconfig.h: No such file or directory
   25 | #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[3]: *** [CMakeFiles/test_dcmtk.dir/build.make:83: CMakeFiles/test_dcmtk.dir/main.cpp.o] Error 1
make[2]: *** [CMakeFiles/Makefile2:96: CMakeFiles/test_dcmtk.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:103: CMakeFiles/test_dcmtk.dir/rule] Error 2
make: *** [Makefile:138: test_dcmtk] Error 2

The difference between both errors is in the headers that the compiler is seeking. In the second case, it looks like the compiler does not understand where osconfig.h is. As this concerns files from DCMTK installation, it is my understanding that they should work as is, which leads me to the thought that this problem should be solved with CMake. However I have absolutely no idea ho make thinghs right in my CMakeLists.txt... And by this, I mean to say that this file contains

cmake_minimum_required(VERSION 3.16)
project(test_dcmtk)

set(CMAKE_CXX_STANDARD 20)

add_executable(test_dcmtk main.cpp)

And I have absolutely no idea what to write here. Could someone please help me?

Thank you in advance !


Solution

  • DCMTK sadly does not provide correctly exported CMake targets, so you will have to patch around that. I installed DCMTK via vcpkg and was able to compile your code with this build (after replacing COUT with std::cout and including iostream):

    cmake_minimum_required(VERSION 3.19)
    project(test_dcmtk)
    
    set(CMAKE_CXX_STANDARD 20)
    
    find_package(DCMTK REQUIRED)
    
    # Wrap the variables that DCMTK sets with a proper imported target
    # These three lines ought not to be needed.
    # This is a failure on the part of the DCMTK authors.
    add_library(DCMTK::DCMTK INTERFACE IMPORTED)
    target_link_libraries(DCMTK::DCMTK INTERFACE ${DCMTK_LIBRARIES})
    target_include_directories(DCMTK::DCMTK INTERFACE ${DCMTK_INCLUDE_DIRS})
    
    # Create your executable and link it to the library
    add_executable(test_dcmtk main.cpp)
    target_link_libraries(test_dcmtk PRIVATE DCMTK::DCMTK)
    

    You should complain to the DCMTK library authors that they don't supply a correct imported target.