Create a Command Line Tool using CMake on macOS#

This topic describes the steps needed to configure a CMake project for C++ Command Line Tool. These steps have been verified to work with Xcode 15.0.1, on macOS Ventura 13.5.2.

Test that you have all tools installed#

C++ Compiler (clang):

clang --version

CMake:

cmake --version

ninja:

ninja --version

If you don’t have those tools follow the steps in the Setup C++ development environment on macOS post to configure a C++ development environment.

Create the project directory#

mkdir -p ~/primoburner/cmake/enum-devices

Create the CMake project#

Switch to the project directory:

cd ~/primoburner/cmake/enum-devices

Add src/main.cpp:

#include <iostream>

int main() {
  std::cout << "Hello PrimoBurner!\n";
}

Add CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)

project(enum-devices)

add_executable(enum-devices src/main.cpp)

Add build.sh:

#!/usr/bin/env bash

mkdir -p ./build/debug
pushd ./build/debug
    cmake -G 'Ninja' -DCMAKE_BUILD_TYPE=Debug  ../.. && \
    ninja
    ret=$?
popd  

Add .gitignore:

.DS_Store
.cache/
build/

You should end up with the following directory structure:

tree -a -L 2 enum-devices

enum-devices
├── .gitignore
├── CMakeLists.txt
├── build.sh
└── src
    └── main.cpp

Test the build#

chmod +x build.sh

./build.sh

Update for PrimoBurner#

  1. Download the 64 bit version of PrimoBurner for C++ (macOS). The file you need will have a name similar to primoburner-v5.0.1-demo.1-darwin.zip except for the version number which may be different.

  2. Extract the ZIP archive in a location of your choice, then copy the include and lib directories to the primoburner subdirectory of the CMake project directory. The CMake project directory is the directory that contains the CMakeLists.txt file.

    You should end up with a directory structure similar to the following:

    enum-devices
    ├── .gitignore
    ├── CMakeLists.txt
    ├── primoburner
    │   ├── include
    │   └── lib
    ├── build.sh
    └── src
        └── main.cpp
    
  3. Replace the contents of .gitignore with this code:

    .DS_Store
    .cache/
    build/
    primoburner/
    
  4. Replace the contents of CMakeLists.txt with this code:

    cmake_minimum_required(VERSION 3.16)
    
    project(enum-devices)
    set (target enum-devices)
    
    add_executable(${target})
    
    # definitions for Debug x64
    target_compile_definitions(${target} PUBLIC  _DEBUG)
    
    # compile options for Debug x64
    target_compile_options(${target} PRIVATE -std=c++20 -stdlib=libc++)
    target_compile_options(${target} PRIVATE -m64 -fPIC)
    target_compile_options(${target} PRIVATE -g)
    
    # includes
    target_include_directories(${target} PUBLIC primoburner/include)
    
    # libs
    target_link_directories(${target} PRIVATE ${PROJECT_SOURCE_DIR}/primoburner/lib/x64)
    target_link_libraries(${target} libPrimoBurner.dylib "-framework CoreFoundation" "-framework AppKit")
    
    # sources
    file(GLOB source "src/*.cpp" "src/*.mm")
    target_sources(${target} PRIVATE ${source})
    
  5. Replace the contents of main.cpp with this code:

    //
    //  main.cpp
    //  enum-devices
    //
    
    #include <iostream>
    
    #include <primo/burner/pb.h>
    #include <primo/platform/ustring.h>
    #include <primo/platform/reference++.h>
    
    namespace p = primo;
    namespace pb = primo::burner;
    
    int main(int argc, const char * argv[]) {
        // Create engine
        auto engine = p::make_ref(pb::Library::createEngine());
    
        // Initialize engine
        engine->initialize();
    
        // create device enumerator
        auto enumerator = p::make_ref(engine->createDeviceEnumerator());
    
        for (int i = 0; i < enumerator->count(); i++) {
            // create a device; do not ask for exclusive access
            auto device = p::make_ref(enumerator->createDevice(i, false));
            
            if (device) {
                using namespace std;
    
                auto description = p::ustring(device->description());
    
                cout << "Device       : " << i << endl;
                cout << "Description  : " << description.str() << endl;
    
                cout << endl;
            }
        }
    
        // terminate engine
        engine->shutdown();
        
        return 0;
    }
    
  6. Build the project

    ./build.sh
    

Run the application#

./build/debug/enum-devices

You should see a list of all CD / DVD / BD devices that are connected to the system.