Building for NixOS

I’ve been daily driving NixOS for a couple of months and recently I changed jobs and started working with medical imaging where Orthanc has been fantastic :pray:

To my surprise, Orthanc is not present in the nix package manager, so I wanted to give it a try and contribute it upstream.

I’m not familiar with building C++ projects and I’ve encountering an issue I’ve not been able to get around. Here are the error logs:

CMake Error at /build/hg-archive/OrthancFramework/Resources/CMake/DcmtkConfiguration.cmake:312 (message):
  Cannot locate the DICOM dictionary on this system
Call Stack (most recent call first):
  /build/hg-archive/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake:523 (include)
  CMakeLists.txt:80 (include)

I’ve tried a couple of things, mainly to set -DDCMTK_DICTIONARY_DIR to DCMTK’s dictionary directory:
"-DDCMTK_DICTIONARY_DIR=${pkgs.dcmtk}/share/dcmtk-${pkgs.dcmtk.version}/"
which evaluates to
DDCMTK_DICTIONARY_DIR=/nix/store/wj2r80pwpfndq9xq1v560c5pmgpgsahh-dcmtk-3.6.8/share/dcmtk-3.6.8/".
Locally inspecting the directory, it correctly contains the dicom.dic file, which I think it was it’s searching for?

If you have any suggestion on how to deal with this, it would be very helpful!

Here is a repo if you want to reproduce the error https://github.com/dvcorreia/healthcare-oss-flake.
To build, go to pkgs/orthanc and run docker build ..

Hello,

I don’t know the Nix build process but gave it a try.

I think your CMake flags are not taken into account.

First I changed this line:

cmake ../OrthancServer/

to

cmake -DDCMTK_DICTIONARY_DIR="${pkgs.dcmtk}/share/dcmtk-${pkgs.dcmtk.version}"  ../OrthancServer/

Which allowed the build to proceed a little further.

But then it complained about:

CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON

It made sense.

I then switched the -DALLOW_DOWNLOADS=OFF-DALLOW_DOWNLOADS=ON in the cmakeFlags list (just to check if the CMake flags are indeed passed) and the error was the same, which seems to suggest that the flags are not taken into account.

Then, I simply replaced the cmake invocation with:

cmake -DALLOW_DOWNLOADS=ON -DSTATIC_BUILD=OFF -DCMAKE_BUILD_TYPE=Debug -DUSE_SYSTEM_DCMTK=OFF -DSTANDALONE_BUILD=ON -DDCMTK_DICTIONARY_DIR="${pkgs.dcmtk}/share/dcmtk-${pkgs.dcmtk.version}" ../OrthancServer/

and the build proceeded…
(it will be very slow with make without -j flag, by the way)

I don’t know how CMake works in Nix, but it seems that passing CMake variables must be done differently, unless I made a mistake.

Also, I do not know why the “bare” invocation that you used triggered a dictionary lookup failure, and merely specifying it triggered the download process (hence the error). It sounds a bit strange that Orthanc tries to find the dictionary before downloading DCMTK. I don’t know the Orthanc build system well (it’s pretty complex and powerful) but you might want to fork the Orthanc repo and add a couple of diagnostic messages here and there to better understand the CMake flow.

Also, it seems that your combination of CMake flags cannot work. Since you specify -DUSE_SYSTEM_DCMTK=OFF, Orthanc needs to download DCMTK (unless you provide Orthanc with a pre-downloaded archive), which you want to prevent, for very good reasons, I assume, with -DALLOW_DOWNLOADS=ON). I think you might want to let the build use the system DCMTK, provided a suitable version is available.

Hope this helps,

And, btw, the link failed.
Missing symbol:

_ZN4absl12lts_2024011612log_internal17MakeCheckOpStringIPKvS4_EEPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_T0_PKc

which is

std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >* absl::lts_20240116::log_internal::MakeCheckOpString<void const*, void const*>(void const*, void const*, char const*)

Could be related to protobuf. You might want to Google around. A workaround for a similar issue is listed here: C++: Undefine reference to functions defined in absl::lts_20230125 · Issue #12292 · protocolbuffers/protobuf (github.com)

And the fix was to forcefully reference two items in the link (I honestly don’t understand this at all at this stage) :

find_package( absl REQUIRED )
find_package( Protobuf 3.21 REQUIRED )   # already in Orthanc !
# ...
target_link_libraries(
    ${Protobuf_LIBRARIES}
    absl::log_internal_message
    absl::log_internal_check_op
)

(this probably means that, unless you accept to replace some dependencies with non-system ones, you’ll have to maintain patches on top of the Orthanc source code… I don’t think it’s surprising, btw. I guess most package maintainers have to slightly adapt the build system of the library/application they want to package)

I have a feeling you’re not done yet.
Good luck !

Hello,

Thanks for your positive feedback about Orthanc, for trying to package Orthanc for NixOS, and for providing this Docker file!

Please find attached a patch that allows to fix the build, without using any network connection and without recompiling DCMTK from scratch.

A few remarks:

  • As already noticed by Benjamin, the parameter cmakeFlags seems to be simply ignored, so I removed it and provided CMake arguments manually while invoking the cmake command. NixOS developers (I’m not one of them) should be able to explain how to more elegantly handle this issue.
  • I have disabled the build of the “ConnectivityChecks” sample plugin for Orthanc, as this one requires either an Internet connection during the build (i.e., -DALLOW_DOWNLOADS=ON) or a manual pre-population of the ThirdPartyDownloads folders.
  • I have disabled the build of the “MultitenantDicom” sample plugin for Orthanc, as there is a linking problem I couldn’t readily understand.
  • I have manually enabled multi-processing when invoking make to speed up the build, but NixOS provides cleaner ways of doing so (cf. the arguments --max-jobs and --cores of nix-build). Again, NixOS developers could help here.
  • I have added the execution of the unit tests as a build step for quality assurance.

Now, there is one remaining big issue: Orthanc and its unit tests simply don’t run, because the standard file /etc/localtime is missing in the standard environment of NixOS. From what I understand, this is because the localtimed service is not running during the build and during the runtime in the stdenv environment. I have found different references on Internet that talk about setting the following options:

services.geoclue2.enable = true;
services.localtimed.enable = true;

However, those options do not seem to work if included in your orthanc.nix file. I was not able to find a quick solution, so I guess your best bet is (again) to get in touch with NixOS developers to know how to start the localtimed service during the buildPhase and as a runtime dependency. Please keep us updated!

Kind Regards,
Sébastien-

nix.patch.txt (896 Bytes)

1 Like

Update: I have just managed to also compile the “MultitenantDicom” sample plugin using the patch attached to this message.

nix-2.patch.txt (872 Bytes)

I was able to build Orthanc successfully! At first sight, all the features I usually use seem to be working as expected. Thank you for all the help, Benjamin and Sábastien.

The issue with the /etc/localtime is something I will have to look how to deal with in the checkPhase. In my local NixOS system /etc/localtime exits, so I was able to run the unit tests outside the nix derivation and everything seems ok! Here are the results for reference https://gist.github.com/dvcorreia/ef06c228d6d724d00821b234ee157c3c.

I’m thinking on adding support for Darwin next.
Then, deal with plugins and add declarations for people to configure and host it with NixOS. By this point, it should be ready to contribute upstream to nix packages.
I’m fairly inexperienced with nix, so this can take some time.

1 Like

In the derivation I specify two types of dependencies:

  • nativeBuildInputs the build-time dependencies
  • buildInputs: runtime dependencies

Is there any build-time dependencies that are in fact runtime ones?

nativeBuildInputs = with pkgs; [
    gnumake
    cmake
    python3
    curl
    gtest
    protobuf
  ];

  buildInputs = with pkgs; [
    libgcc
    unzip
    sqlite
    openssl
    civetweb
    libjpeg
    libpng
    lua
    pugixml
    jsoncpp
    libuuid
    boost
    dcmtk # implements the dicom standard
    #sqlitecpp
    #gflags
    locale
  ];

Hello,

It seems correct to me (I am far from being an expert of the Orthanc build system).

(I do not know how you plan to package plugins, but they will have their own dependencies. For instance, the Python plugin will require python3 and it should become a runtime dependency there)