Development environment for C++ with Qt compiled from source

I’m trying to setup a development environment for out team. The requirements are as follows:

  • Host OS is Ubuntu 24.04, nix is installed in single-user-mode (due to some IT restrictions).
  • flake-based with nix-direnv for ease of use.
  • C++ application, i.e. compiler, build system etc. need to be setup, as well as conan to compile dependencies.

A basic version of this looks currently like this (very much based on this):

{
  description = "A Nix-flake-based C/C++ development environment";
  inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1.*.tar.gz";
  outputs = { self, nixpkgs }:
    let
      supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
      forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f system);
    in
    {
      devShells = forEachSupportedSystem (system:
        let
          pkgs = import nixpkgs { inherit system; };
        in {
          default = pkgs.mkShell.override
            {
              # Override stdenv in order to change compiler:
              # stdenv = pkgs.clangStdenv;
            }
            {
              packages = let
                pkgs_clang_tools = import (builtins.fetchGit {
                    name = "clang_tools";
                    url = "https://github.com/NixOS/nixpkgs/";
                    ref = "refs/heads/nixos-unstable";
                    rev = "47c1824c261a343a6acca36d168a0a86f0e66292";
                }) {inherit system;};
              in [
                pkgs_clang_tools.llvmPackages_15.clang-tools
                pkgs_clang_tools.llvmPackages_15.clang
                pkgs.cmake
                pkgs.conan
                pkgs.doxygen
		pkgs.ninja
              ];
            };
        });
    };
}

This works quite nicely, i.e. I can use all the tools I need and a small test application seems to compile just fine.

My problem is currently that some of the dependencies that we build have “system dependencies”, i.e. things that package expects the host to provide which are not really managed by a C++ dependency manager. To make a specific example: we use Qt6, which in turn has a list of dependencies, which you on Ubuntu normally install over

apt install \
    libfontconfig1-dev \
    libfreetype-dev \
    libx11-dev \
    libx11-xcb-dev \
    libxcb-cursor-dev \
    libxcb-glx0-dev \
    libxcb-icccm4-dev \
    libxcb-image0-dev \
    libxcb-keysyms1-dev \
    libxcb-randr0-dev \
    libxcb-render-util0-dev \
    libxcb-shape0-dev \
    libxcb-shm0-dev \
    libxcb-sync-dev \
    libxcb-util-dev \
    libxcb-xfixes0-dev \
    libxcb-xinerama0-dev \
    libxcb-xkb-dev \
    libxcb1-dev \
    libxext-dev \
    libxfixes-dev \
    libxi-dev \
    libxkbcommon-dev \
    libxkbcommon-x11-dev \
    libxrender-dev

Now, if I understand nixs role as package manager correctly then it should be able to replace this part of apt as well. What I dont want to use is the qt6 version that nixpkgs provides, we need to compile it ourselves, i.e. I need to find all these dependencies.

This is ofc. fine by me (especially since there is already a qt6 package (see here)), but before I start on this quest I wanted to check if this is the “correct” way to create such a development environment. I’m aware that there are probably more than one way to do this, and using a independent package manager like conan defeats the purpose of nix to some degree, but what we are looking for is a way to quickly setup a reproducible development environment. Should nix be used for something like this? Is this too little commitment?
I’ve played around with nix for a few months and used it to configure development environments, but this Qt thingy is certainly a bit more complicated than Im used to.

Can you explain why? In case you need to apply some specific patches to qt6, then nix provides some pretty good facilities with override and overrideAttrs.

Mixing package managers often results in a worst or both worlds situation, but it could still be a reasonable starting point for you. I would recommend to make sure that all dependencies that are provided in binary form are coming from the nix, so that you can take advantage of binary caches.

Lastly I would recommend looking into devenv, which could be used instead of a flake or plain shell.nix, as that provides a better out-of-the-box and onboarding experience than the former two.