# macOS

See example [New experimental Recipe for MacOS (Silicon)](#recipe-for-macos-silicon) below.

## Prerequisites

The prerequisites listed below are required to be able to configure/build/package/test Slicer.

- XCode command line tools must be installed:

```console
xcode-select --install
```

- A CMake version that meets at least the minimum required CMake version [here](https://github.com/Slicer/Slicer/blob/main/CMakeLists.txt#L1).
- Qt 5: **tested and recommended**.
  - For building Slicer: download and execute [qt-online-installer-mac-x64-online.dmg](https://download.qt.io/official_releases/online_installers/qt-online-installer-mac-x64-online.dmg), install Qt 5.15.2, make sure to select the `qtwebengine` component.
  - For packaging and redistributing Slicer: build Qt using [qt-easy-build](https://github.com/jcfr/qt-easy-build#readme)
- Setting `CMAKE_OSX_DEPLOYMENT_TARGET` CMake variable specifies the minimum macOS version a generated installer may target. So it should be equal to or less than the version of SDK you are building on. Note that the SDK version is set using `CMAKE_OSX_SYSROOT` CMake variable automatically initialized during CMake configuration.

## Checkout Slicer source files

Notes:

- While it is not enforced, we strongly recommend you to *avoid* the use of *spaces* for both the `source directory` and the `build directory`.
- Due to maximum path length limitations during the build process, build folders must be located in a location with very short total path length. This is especially critical on Windows and macOS. For example, `/opt/s` has been confirmed to work on macOS.

Check out the code using `git`:

- Clone the github repository

```console
git clone https://github.com/Slicer/Slicer.git
```

The `Slicer` directory is automatically created after cloning Slicer.

- Setup the development environment:

```console
cd Slicer
./Utilities/SetupForDevelopment.sh
```

## Configure and generate Slicer solution files

- Configure using the following commands. By default `CMAKE_BUILD_TYPE` is set to `Debug` (replace `/path/to/Qt` with the real path on your machine where QtSDK is located):

```console
mkdir /opt/s
cd /opt/s
cmake \
  -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=14.0 \
  -DCMAKE_BUILD_TYPE:STRING=Debug \
  -DQt5_DIR:PATH=/path/to/Qt/lib/cmake/Qt5 \
  /path/to/source/code/of/Slicer
```

- If `using Qt from the system`, do not forget to add the following CMake variable to your configuration command line: `-DSlicer_USE_SYSTEM_QT:BOOL=ON`

- Remarks:
  - Instead of `cmake`, you can use `ccmake` or `cmake-gui` to visually inspect and edit configure options.
  - Using top-level directory name like `/opt/sr` for Release or `/opt/s` for Debug is recommended. If `/opt` does not exist on your machine you need to use sudo for `mkdir` and `chown` in `/opt`.
  - [Step-by-step debug instructions](https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/Debug_Instructions)
  - Additional configuration options to customize the application are described [here](overview.md#custom-builds).

### General information

Two projects are generated by either `cmake`, `ccmake` or `cmake-gui`. One of them is in the top-level bin directory `/opt/s` and the other one is in the subdirectory `Slicer-build`:

- `/opt/s` manages all the external dependencies of Slicer (VTK, ITK, Python, ...). To build Slicer for the first time, run `make` in `/opt/s`, which will update and build the external libraries and if successful will then build the subproject `Slicer-build`.
- `/opt/s/Slicer-build` is the "traditional" build directory of Slicer. After local changes in Slicer (or after an git update on the source directory of Slicer), only running `make` in `/opt/s/Slicer-build` is necessary (the external libraries are considered built and up to date).

*Warning:* An significant amount of disk space is required to compile Slicer in Debug mode (>20GB)

*Warning:* Some firewalls will block the git protocol. See more information and solution [here](common_errors.md#firewall-is-blocking-git-protocol).

## Build Slicer

After configuration, start the build process in the `/opt/s` directory

- Start a terminal and type the following (you can replace 4 by the number of processor cores in the computer. You can find out the number of available cores by running `sysctl -n hw.ncpu`):

```console
cd ~/opt/s
make -j4
```

## Run Slicer

Start a terminal and type the following:

```console
/opt/s/Slicer-build/Slicer
```

## Test Slicer

After building, run the tests in the `/opt/s/Slicer-build` directory.

Start a terminal and type the following (you can replace 4 by the number of processor cores in the computer):

```console
cd /opt/s/Slicer-build
ctest -j4
```

## Package Slicer

*Warning:* Slicer will **only** create a valid package that will run on machines other than it's built on if Qt was built from source.

Start a terminal and type the following:

```console
cd /opt/s
cd Slicer-build
make package
```

### Debugging the build process

When using the `-j` option, the build will continue past the source of the first error. If the build fails and you don't see what failed, rebuild without the `-j` option. Or, to speed up this process build first with the `-j` and `-k` options and then run plain make. The `-k` option will make the build keep going so that any code that can be compiled independent of the error will be completed and the second make will reach the error condition more efficiently. To debug the error you can pipe the output of the make command to an external log file like this:

```console
make -j10 -k; make 2>&1 | tee /tmp/build.log
```

In some cases when the build fails without explicitly stating what went wrong it's useful to look at error logs created during building of individual packages bundled with Slicer. Running the following command in the `/opt/s` folder

```console
find . -name "*rr*.log" | xargs ls -ltur
```

will list such error logs in ordered by the time of latest access. The log that was accessed the last will be the lowest one in the list.


### error while configuring PCRE: "cannot run C compiled program"

If the XCode command line tools are not properly set up on macOS, PCRE could fail to build in the Superbuild process with the errors like below:

```console
configure: error: in `/Users/fedorov/local/Slicer4-Debug/PCRE-build':
configure: error: cannot run C compiled programs.
```

To install XCode command line tools, use the following command from the terminal:

```console
xcode-select --install
```

### dyld: malformed mach-o: load commands size (...) > 32768

Path the build folder is too long. For example building Slicer in `/User/somebody/projects/something/dev/slicer/slicer-qt5-rel` may fail with malformed mach-o error, while it succeeds in `/opt/s` folder. To resolve this error, move the build folder to a location with shorter full path and restart the build from scratch (the build tree is not relocatable).

### Packaging errors

#### Fixing @rpath errors during packaging

If an error like

```
warning: target '@rpath/QtGui.framework/Versions/5/QtGui' is not absolute...
warning: target '@rpath/QtGui.framework/Versions/5/QtGui' does not exist...
```

is present during packaging - doublecheck that Slicer was built with Qt that was built from source and not Qt that was installed from a web-installer or homebrew.

## Update Homebrew packages

Slicer can be installed with a single command using [Homebrew](https://brew.sh/), as described in the [installation documentation](../../user_guide/getting_started.md#installing-using-homebrew).

Specifically, the `cask` extension is used, which allows management of graphical applications from the command line.
Casks are Ruby files (`.rb`) describing the metadata necessary to download, check and install the package.

The [cask for the Preview version of Slicer](https://github.com/Homebrew/homebrew-cask-versions/blob/master/Casks/slicer-preview.rb) does not need maintenance, as it automatically downloads the latest binaries and therefore the exact version does not need to be specified in the cask.
However, the [cask for the stable version](https://github.com/Homebrew/homebrew-cask/blob/master/Casks/slicer.rb), which has traditionally been [maintained by Slicer users](https://github.com/Homebrew/homebrew-cask/commits/master/Casks/slicer.rb), needs to be manually updated every time a new stable version of Slicer is released.
Instructions to update Homebrew casks can be found on the [`homebrew-cask` repository](https://github.com/Homebrew/homebrew-cask/blob/HEAD/CONTRIBUTING.md#updating-a-cask).
This is an example of a command that can be used to update the cask for a Stable release:

```shell
$ brew bump-cask-pr --version 4.11.20210226,1442768 slicer
```

To install `brew`, the following command can be run:

```shell
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

## Common errors

See list of issues common to all operating systems on [Common errors](common_errors.md) page.

--

## Recipe for MacOS on arm64 (New, work in progress)

Issues are being tracked here: https://github.com/Slicer/Slicer/issues/6811

### Example config:
```
frolick@IsabelMacBook % sw_vers
ProductName:		macOS
ProductVersion:		15.7.3
BuildVersion:		24G419

frolick@IsabelMacBook % qmake --version
QMake version 3.1
Using Qt version 6.10.1 in /opt/homebrew/lib

frolick@IsabelMacBook % cmake --version
cmake version 3.31.5

CMake suite maintained and supported by Kitware (kitware.com/cmake).

frolick@IsabelMacBook % system_profiler SPHardwareDataType

Hardware:
    Hardware Overview:
      Model Name: MacBook Pro
      Model Identifier: Mac15,6
      Chip: Apple M3 Pro
      Total Number of Cores: 11 (5 performance and 6 efficiency)
      Memory: 36 GB
```

##### Prerequisites

###### Install Qt6

Verify Qt6 Install
```
qmake --version
```

1. If not installed, Install Qt6 (via Homebrew)
```
brew install qt@6

#Add Qt6 to shell environment
echo 'export PATH="/opt/homebrew/opt/qt@6/bin:$PATH"' >> ~/.zshrc
echo 'export CMAKE_PREFIX_PATH="/opt/homebrew/opt/qt@6:$CMAKE_PREFIX_PATH"' >> ~/.zshrc

#Reload shell
source ~/.zshrc

#Verify Qt6 installation
qmake --version
```

###### Install Xcode Command Line Tools
```
xcode-select --install
```

###### Install XCode (not strictly necessary (?) but I couldn't do it without XCode Desktop)


If installing full Xcode from the App Store:
```
#Set it as the active developer directory
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer

#Accept the license
sudo xcodebuild -license accept

#Verify
xcodebuild -version
xcode-select -p
#Should return something like: /Applications/Xcode.app/Contents/Developer
```


Else, check the SDK path used by Xcode:
```
xcrun --show-sdk-path

#Should return something like:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk

```
---

##### Directory Setup

Create build directories and set ownership:
```
sudo mkdir -p /opt/scmake /opt/scd
sudo chown -R $(whoami) /opt/scmake /opt/scd
```

##### Create Build Script

```
vim build_slicer.sh
```

Paste into script:
```
#!/bin/bash

# Configuration
SLICER_SOURCE_DIR="$HOME/slicer/latest/Slicer"
SLICER_BUILD_DIR="/opt/scd"
SLICER_SUPERBUILD_DIR="/opt/scmake"

# Create directories
mkdir -p "$SLICER_BUILD_DIR"
mkdir -p "$SLICER_SUPERBUILD_DIR"

# Clone Slicer source if it doesn't exist
if [ ! -d "$SLICER_SOURCE_DIR" ]; then
    echo "Cloning Slicer repository..."
    mkdir -p "$(dirname "$SLICER_SOURCE_DIR")"
    git clone https://github.com/Slicer/Slicer.git "$SLICER_SOURCE_DIR"
fi

cd "$SLICER_SUPERBUILD_DIR"

# Configure with CMake
cmake \
  -DCMAKE_OSX_ARCHITECTURES=arm64 \ #CHANGE ME: OSX architecture (uname -m)
  -DSlicer_REQUIRED_QT_VERSION="6.10" \ # CHANGEME: Qt version (qmake --version)
  -DCMAKE_BUILD_TYPE:STRING=Debug \
  -DSlicer_USE_SimpleITK:BOOL=OFF \
  -DSlicer_BUILD_I18N_SUPPORT:BOOL=OFF \
  -DSlicer_BUILD_DICOM_SUPPORT:BOOL=OFF \
  -DSlicer_VTK_SMP_IMPLEMENTATION_TYPE:STRING=Sequential \
  -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=15.7 \ # CHANGEME: OSX version (About this Mac -> macOS)
  -DCMAKE_OSX_SYSROOT:STRING="$(xcrun --show-sdk-path)" \
  "$SLICER_SOURCE_DIR"

# Build (use -j for parallel jobs, -k to keep going on errors)
make -j10 -k
```


##### Run Build

```
cd /opt/scmake
chmod +x ./build_slicer.sh
./build_slicer.sh
```


---

##### Running Slicer Locally

###### Option 1: Navigate to the build directory, make, launch:
Executable path: /opt/scmake/Slicer-build/Slicer

```
cd /opt/scmake/Slicer-build
make -j8 #Optional rebuild to show local changes
./Slicer
```

###### Option 2: Run on XCode with Debugging

Create a Dummy Xcode Project
  Xcode requires an open project in order to attach a debugger.
  1. Open Xcode
  2. File → New → Project
  3. Create a Command Line Tool project (macOS)
  4. Enter an Organization Name (required!)

Get the Slicer Process ID (PID)
   1. Open local Slicer through the build directory (following the steps in Option (1)
   2. In Python Interactor:
      ```
      import os
      os.getpid()
      ```
      Copy the PID
3. Attach the Debugger
   In Xcode:
   1. Debug → Attach to Process by Name or PID…
   2. Paste the PID
   3. Now you can attach process and use debugger functionality (breakpoints, etc.) as usual
