diff --git a/CMakeLists.txt b/CMakeLists.txt index 4921c68..7886088 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,12 +42,26 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 20) set(CMAKE_INCLUDE_CURRENT_DIR ON) -find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core Multimedia) -find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Concurrent Gui Multimedia MultimediaWidgets Network SerialPort Widgets Xml) +option(BUILD_UI "Build GUI applications and UI libraries" ON) -qt_standard_project_setup(REQUIRES 6.9) +if(BUILD_UI) + find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core Multimedia) + find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Concurrent Gui Multimedia MultimediaWidgets Network SerialPort Widgets Xml) +else() + find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core) + find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Concurrent Core Network SerialPort Xml) +endif() + +qt_standard_project_setup(REQUIRES 6.8) +include(GNUInstallDirs) add_subdirectory(third-party) add_subdirectory(src/libraries) -add_subdirectory(src/applications) +if(BUILD_UI) + add_subdirectory(src/applications) +endif() add_subdirectory(interfaces) + +install(DIRECTORY configurations/ + DESTINATION ${CMAKE_INSTALL_DATADIR}/qtac/configurations +) diff --git a/README.md b/README.md index c3478e5..ee7ce6a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ - [Common Prerequisites](#common-prerequisites) - [Windows Guide](#windows-guide) - [Linux Guide](#linux-guide) +- [macOS Guide](#macos-guide) +- [Installing QTAC](#installing-qtac) - [Repository Structure](#repository-structure) - [Application Dependency Architecture](#application-dependency-architecture) - [Advanced Topics](#advanced-topics) @@ -80,16 +82,33 @@ git clone https://github.com/qualcomm/qcom-test-automation-controller.git ### Configuration -1. **Visual Studio**: Install **Desktop development with C++** and **.NET desktop development**. +1. **Git**: Install [Git for Windows](https://git-scm.com/download/win). + +2. **Visual Studio 2022**: Install the + [Community](https://aka.ms/vs/17/release/vs_community.exe), + Professional, or Enterprise edition and select the following workloads: + - **Desktop development with C++** (required — provides MSVC compiler, CMake, and Ninja) + - **.NET desktop development** (required for C# interop builds) + ![Desktop development with C++](./docs/resources/qtac-msvc-2022-requirements.png) -2. **Qt**: Install Qt 6.9+ for **MSVC 2022 64-bit**, **Qt Serial Port** and **Qt Multimedia** components. - -> [!NOTE] -> Installation using Qt Online Installer will require users to create a Qt account. -3. **Environment Variable**: + + > [!NOTE] + > CMake 3.16+ and Ninja are bundled with Visual Studio; no separate installation needed. + +3. **Qt 6.8+**: Use the [Qt Online Installer](https://www.qt.io/download-qt-installer-oss) + and select the following for the **MSVC 2022 64-bit** target: + - Qt 6.8.x → **MSVC 2022 64-bit** (compiler binaries) + - Qt 6.8.x → **Qt Serial Port** + - Qt 6.8.x → **Qt Multimedia** + + > [!NOTE] + > Installation using Qt Online Installer requires a Qt account. + +4. **Environment Variable** — set `QTBIN` permanently in your user environment: ```cmd setx QTBIN C:\Qt\\msvc2022_64\bin ``` + Open a new command prompt after running `setx` for the change to take effect. ### Build & Usage @@ -99,8 +118,18 @@ Execute `build.bat` to generate executables: build.bat ``` +**Build options**: +| Flag | Description | +| :-- | :-- | +| `--pristine` | Delete `build\`, `__Builds\`, and cached downloads before building (default) | +| `--incremental` | Reuse existing build tree and downloaded libraries | +| `--no-gui` | Build only headless libraries (`QCommonConsole`, `TACDev`) without Qt GUI modules or applications | +| `--debug` | Also build a Debug configuration (Release is always built) | +| `--install` | Install binaries, libraries, headers, and configs to `CMAKE_INSTALL_PREFIX` (default: `C:\Program Files\QTAC`); requires Administrator | +| `--deploy` | Run `windeployqt` to bundle Qt DLLs into each app directory (slow; use for distribution packages) | + **Build output**: -- Debug: `__Builds\x64\Debug` +- Debug (with `--debug`): `__Builds\x64\Debug` - Release: `__Builds\x64\Release` **Usage**: @@ -115,25 +144,57 @@ __Builds\x64\Release\QTAC.exe > [!IMPORTANT] > - Installation using Qt Online Installer will require users to create a Qt account. > - If you're frequently working with Qt on Linux, consider adding the environment variables to `.bashrc`. -> - Using `sudo apt install ` will update setup packages. Review command usage to prevent issues with other applications. - -1. **Qt Installation** (choose one): - - **Option A**: Qt Online Installer - - Install Qt 6.9+ for **GCC 64-bit** and **Qt Serial Port** component using [Qt Online Installer](https://www.qt.io/download-qt-installer-oss) - - **Option B**: Quick Installation via apt + +1. **Build Tools**: ```bash - sudo apt install qt6-base-dev qt6-serialport-dev + sudo apt install cmake build-essential ninja-build git ``` -2. **Runtime Dependencies**: + - `cmake` 3.16 or later + - `build-essential` — GCC/G++ 11 or later and make + - `ninja-build` — faster parallel builds (recommended) + +2. **Qt 6.8+** (choose one): + + **Option A**: System Qt via apt (Ubuntu 24.04+ / Debian 13+) + ```bash + sudo apt install qt6-base-dev qt6-multimedia-dev qt6-serialport-dev qt6-tools-dev + ``` + > [!NOTE] + > Ubuntu 22.04 ships Qt 6.2 which is too old. Use Option B or C on 22.04. + + For `--no-gui` builds only `QCommonConsole` and `TACDev` are compiled, so fewer Qt + packages are needed: + ```bash + sudo apt install qt6-base-dev qt6-serialport-dev qt6-tools-dev + ``` + + **Option B**: Qt Online Installer (any distro / Ubuntu version) + - Install Qt 6.8+ for **GCC 64-bit**, selecting the **Qt Serial Port** and + **Qt Multimedia** components using the + [Qt Online Installer](https://www.qt.io/download-qt-installer-oss) + + **Option C**: aqtinstall (scriptable, no Qt account required) + ```bash + pip install aqtinstall + aqt install-qt linux desktop 6.8.0 gcc_64 -m qtserialport qtmultimedia + ``` + +3. **USB Access** — install the udev rule so the debug board is accessible without root: ```bash sudo cp udev-rules/99-QTAC-USB.rules /etc/udev/rules.d/ sudo udevadm control --reload + sudo udevadm trigger + ``` + +4. **Environment Variable** — set `QTBIN` to the Qt `bin/` directory: + + System Qt (apt): + ```bash + export QTBIN=/usr/lib/qt6/bin ``` -4. **Environment Variable**: + Qt Online Installer or aqtinstall: ```bash - export QTBIN=/path/to/Qt/directory//gcc_64/bin + export QTBIN=~/Qt/6.8.0/gcc_64/bin ``` ### Build & Usage @@ -144,18 +205,178 @@ Execute `build.sh` to generate executables: ./build.sh ``` +**Build options**: +| Flag | Description | +| :-- | :-- | +| `--pristine` | Delete `build/`, `__Builds/`, and cached downloads before building (default) | +| `--incremental` | Reuse the existing build tree; skip the clean step. | +| `--no-gui` | Build only headless libraries (`QCommonConsole`, `TACDev`) without Qt GUI modules or applications; omits Qt Multimedia, Widgets, `qcommon`, `ui-common`, and all GUI apps | +| `--debug` | Also build a Debug configuration (Release is always built). | +| `--install` | Install binaries, libraries, headers, and configs to `CMAKE_INSTALL_PREFIX` (default: `/usr/local`); invokes `sudo cmake --install` | +| `--deploy` | Run `macdeployqt` to bundle Qt frameworks into each app bundle (slow; use for distribution packages; macOS only) | + +**No-GUI build** — omits Qt Multimedia, Qt Widgets, `qcommon`, `ui-common`, and all GUI +applications. Only `QCommonConsole` and `TACDev` are compiled: + +```bash +./build.sh --no-gui +``` + **Build output**: -- Debug: `__Builds/Linux/Debug` -- Release: `__Builds/Linux/Release` +- Release: `__Builds/Linux-/Release` +- Debug (with `--debug`): `__Builds/Linux-/Debug` -> [!NOTE] -> Ensure that [make](https://www.gnu.org/software/make/) is available in your environment before building. +**Usage**: +```bash +./__Builds/Linux-$(. /etc/os-release && echo "$ID")/Release/bin/TAC +``` + +## macOS Guide + +### Configuration + +1. **Xcode Command Line Tools**: + ```bash + xcode-select --install + ``` + +2. **CMake 3.16+** (choose one): + - Download from [cmake.org](https://cmake.org/download/) + - Or install via Homebrew: `brew install cmake` + +3. **Qt 6.8+** (choose one): + + **Option A**: Homebrew (simplest — includes all required modules) + ```bash + brew install qt + ``` + + **Option B**: Qt Online Installer + - Use the [Qt Online Installer](https://www.qt.io/download-qt-installer-oss) and select + the following for the **macOS** target: + - Qt 6.8.x → **macOS** (compiler binaries) + - Qt 6.8.x → **Qt Serial Port** + - Qt 6.8.x → **Qt Multimedia** + + > [!NOTE] + > Installation using Qt Online Installer requires a Qt account. + +4. **Environment Variable** — set `QTBIN` to the Qt `bin/` directory: + + Homebrew: + ```bash + export QTBIN=$(brew --prefix qt)/bin + ``` + Qt Online Installer: + ```bash + export QTBIN=~/Qt/6.8.0/macos/bin + ``` + +### Build & Usage + +`build.sh` is used on macOS with the same flags as Linux. FTDI D2XX is downloaded +automatically from an FTDI-provided DMG at cmake configure time (requires `hdiutil`, +which is built into macOS). + +```bash +./build.sh +``` + +**Build output**: +- Release: `__Builds/macOS/Release` +- Debug (with `--debug`): `__Builds/macOS/Debug` **Usage**: ```bash -./__Builds/Linux/Release/QTAC +open __Builds/macOS/Release/bin/TAC.app +``` + +## Installing QTAC + +Pass `--install` to `build.sh` or `build.bat` to run `cmake --install` after a successful +build. The default install prefix is `/usr/local` on Linux/macOS and +`C:\Program Files\QTAC` on Windows. Override it by setting `CMAKE_INSTALL_PREFIX` in your +cmake invocation. + +### Linux + +```bash +./build.sh --install +# or, to install to a custom prefix: +cmake --install build/debian/Release --prefix /opt/qtac +``` + +| Installed path | Content | +| :-- | :-- | +| `$PREFIX/bin/TAC` | Test Automation Controller GUI | +| `$PREFIX/bin/TACConfigEditor` | TAC Configuration Editor GUI | +| `$PREFIX/bin/DeviceCatalog` | Device Catalog GUI | +| `$PREFIX/bin/DevList` | List connected debug boards | +| `$PREFIX/bin/TACDump` | Dump TAC configuration | +| `$PREFIX/bin/FTDICheck` | FTDI device diagnostics | +| `$PREFIX/bin/UpdateDeviceList` | Update the device list | +| `$PREFIX/bin/LITEProgrammer` | Program LITE debug boards | +| `$PREFIX/bin/qt.conf` | Qt plugin path for installed binaries | +| `$PREFIX/lib/libTACDev.a` | TACDev C++ static library | +| `$PREFIX/lib/libftd2xx.a` | FTDI D2XX static library | +| `$PREFIX/include/qtac/TACDev.h` | TACDev public header | +| `$PREFIX/share/qtac/configurations/` | Device configuration files (`.tcnf`, `devicelist.json`) | +| `$PREFIX/share/applications/` | `.desktop` files for TAC, TACConfigEditor, DeviceCatalog | +| `$PREFIX/share/icons/` | Application icons | + +Installed binaries have RPATH `$ORIGIN:$ORIGIN/../lib` so they find `libftd2xx.a` at +runtime without needing `LD_LIBRARY_PATH`. + +### Windows + +Run `build.bat --install` from an **Administrator** command prompt. The install step +checks for Administrator privileges and exits if not elevated. + +| Installed path | Content | +| :-- | :-- | +| `$PREFIX\bin\TAC.exe` | Test Automation Controller GUI | +| `$PREFIX\bin\TACConfigEditor.exe` | TAC Configuration Editor GUI | +| `$PREFIX\bin\DeviceCatalog.exe` | Device Catalog GUI | +| `$PREFIX\bin\DevList.exe` | List connected debug boards | +| `$PREFIX\bin\TACDump.exe` | Dump TAC configuration | +| `$PREFIX\bin\FTDICheck.exe` | FTDI device diagnostics | +| `$PREFIX\bin\UpdateDeviceList.exe` | Update the device list | +| `$PREFIX\bin\LITEProgrammer.exe` | Program LITE debug boards | +| `$PREFIX\lib\TACDev.lib` | TACDev C++ static library (Release) | +| `$PREFIX\lib\ftd2xx.lib` | FTDI D2XX static library | +| `$PREFIX\include\qtac\TACDev.h` | TACDev public header | +| `$PREFIX\share\qtac\configurations\` | Device configuration files | + +> [!NOTE] +> Qt DLLs are **not** bundled unless `--deploy` was also passed. Without `--deploy`, +> ensure Qt's `bin\` directory is on `PATH` when running installed binaries. + +### macOS + +```bash +./build.sh --install +# or, to install to a custom prefix: +sudo cmake --install build/macOS/Release --prefix /opt/qtac ``` +| Installed path | Content | +| :-- | :-- | +| `$PREFIX/bin/TAC.app` | Test Automation Controller GUI (app bundle) | +| `$PREFIX/bin/TACConfigEditor.app` | TAC Configuration Editor GUI (app bundle) | +| `$PREFIX/bin/DeviceCatalog.app` | Device Catalog GUI (app bundle) | +| `$PREFIX/bin/DevList` | List connected debug boards | +| `$PREFIX/bin/TACDump` | Dump TAC configuration | +| `$PREFIX/bin/FTDICheck` | FTDI device diagnostics | +| `$PREFIX/bin/UpdateDeviceList` | Update the device list | +| `$PREFIX/bin/LITEProgrammer` | Program LITE debug boards | +| `$PREFIX/lib/libTACDev.a` | TACDev C++ static library | +| `$PREFIX/lib/libftd2xx.a` | FTDI D2XX static library | +| `$PREFIX/include/qtac/TACDev.h` | TACDev public header | +| `$PREFIX/share/qtac/configurations/` | Device configuration files | + +App bundles embed an RPATH pointing to the Qt frameworks directory used at build time. +Pass `--deploy` to run `macdeployqt` and make bundles fully self-contained for distribution. + ## Repository Structure | Directory | Content | diff --git a/build.bat b/build.bat index a713d84..a362d91 100644 --- a/build.bat +++ b/build.bat @@ -39,28 +39,75 @@ if "%QTBIN%"=="" ( exit /b 1 ) +set PRISTINE=1 +set BUILD_UI=ON +set BUILD_DEBUG=0 +set INSTALL=0 +set DEPLOY=0 + +:parse_args +if "%~1"=="--pristine" ( set PRISTINE=1 & shift & goto :parse_args ) +if "%~1"=="--incremental" ( set PRISTINE=0 & shift & goto :parse_args ) +if "%~1"=="--no-gui" ( set BUILD_UI=OFF & shift & goto :parse_args ) +if "%~1"=="--debug" ( set BUILD_DEBUG=1 & shift & goto :parse_args ) +if "%~1"=="--install" ( set INSTALL=1 & shift & goto :parse_args ) +if "%~1"=="--deploy" ( set DEPLOY=1 & shift & goto :parse_args ) +if not "%~1"=="" ( + echo Usage: build.bat [--pristine^|--incremental] [--no-gui] [--debug] [--install] [--deploy] + echo --pristine Delete build\, __Builds\, and cached downloads ^(default^) + echo --incremental Reuse existing build tree and downloaded libraries + echo --no-gui Build just low-level libraries without the UI application + echo --debug Also build Debug configuration ^(Release is always built^) + echo --install Install libraries, headers, applications, and configs + echo --deploy Bundle Qt dependencies into each app ^(slow; for distribution^) + exit /b 1 +) + call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" call "C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvars64.bat" call "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat" set "PATH=%QTBIN%;%PATH%" -if exist build rmdir /s /q build -if exist __Builds rmdir /s /q __Builds +if "%PRISTINE%"=="1" ( + if exist build\Debug rmdir /s /q build\Debug + if exist build\Release rmdir /s /q build\Release + if exist __Builds\x64 rmdir /s /q __Builds\x64 + del /q third-party\*.tgz 2>nul + del /q third-party\*.zip 2>nul +) -cmake -S . -B build\Debug -DCMAKE_PREFIX_PATH="%QTBIN%\.." ^ - -DCMAKE_COLOR_DIAGNOSTICS=ON ^ - -DCMAKE_GENERATOR=Ninja ^ - -DCMAKE_BUILD_TYPE=Debug ^ - -DCMAKE_CXX_FLAGS_INIT=-DQT_QML_DEBUG +if "%BUILD_DEBUG%"=="1" ( + cmake -S . -B build\Debug -DCMAKE_PREFIX_PATH="%QTBIN%\.." ^ + -DCMAKE_COLOR_DIAGNOSTICS=ON ^ + -DCMAKE_GENERATOR=Ninja ^ + -DCMAKE_BUILD_TYPE=Debug ^ + -DBUILD_UI=%BUILD_UI% ^ + -DDEPLOY_APPS=OFF ^ + -DCMAKE_CXX_FLAGS_INIT=-DQT_QML_DEBUG + + cmake --build build\Debug +) -cmake --build build\Debug +set DEPLOY_APPS_FLAG=OFF +if "%DEPLOY%"=="1" set DEPLOY_APPS_FLAG=ON cmake -S . -B build\Release -DCMAKE_PREFIX_PATH="%QTBIN%\.." ^ -DCMAKE_COLOR_DIAGNOSTICS=ON ^ -DCMAKE_GENERATOR=Ninja ^ - -DCMAKE_BUILD_TYPE=Release + -DCMAKE_BUILD_TYPE=Release ^ + -DBUILD_UI=%BUILD_UI% ^ + -DDEPLOY_APPS=%DEPLOY_APPS_FLAG% cmake --build build\Release +if "%INSTALL%"=="1" ( + net session >nul 2>&1 + if errorlevel 1 ( + echo Error: --install requires Administrator privileges. Re-run build.bat as Administrator. + exit /b 1 + ) + cmake --install build\Release +) + echo Check __Builds directory diff --git a/build.sh b/build.sh index 1009d7c..ab80bc1 100644 --- a/build.sh +++ b/build.sh @@ -36,6 +36,33 @@ set -e +PRISTINE=1 +BUILD_UI=ON +BUILD_DEBUG=0 +INSTALL=0 +DEPLOY=0 + +for arg in "$@"; do + case "$arg" in + --pristine) PRISTINE=1 ;; + --incremental) PRISTINE=0 ;; + --no-gui) BUILD_UI=OFF ;; + --debug) BUILD_DEBUG=1 ;; + --install) INSTALL=1 ;; + --deploy) DEPLOY=1 ;; + *) + echo "Usage: $0 [--pristine|--incremental] [--no-gui] [--debug] [--install] [--deploy]" + echo " --pristine Delete build/, __Builds/, and cached downloads (default)" + echo " --incremental Reuse existing build tree and downloaded libraries" + echo " --no-gui Build just low-level libraries without the UI application" + echo " --debug Also build Debug configuration (Release is always built)" + echo " --install Install libraries, headers, applications, and configs" + echo " (installs to CMAKE_INSTALL_PREFIX, default: /usr/local)" + echo " --deploy Bundle Qt dependencies into each app (slow; for distribution)" + exit 1 ;; + esac +done + if [ -z "$QTBIN" ]; then echo "Set QTBIN first" exit 1 @@ -43,15 +70,47 @@ fi export PATH="$QTBIN:$PATH" -# Clean start -rm -rf build __Builds +case "$(uname)" in + Linux) + DISTRO=$(. /etc/os-release && echo "$ID") + CMAKE_DISTRO_FLAG="-DLINUX_DISTRO=${DISTRO}" + NPROC=$(nproc) + BUILDS_SUBDIR="Linux-${DISTRO}" + ;; + Darwin) + DISTRO="macOS" + CMAKE_DISTRO_FLAG="" + NPROC=$(sysctl -n hw.logicalcpu) + BUILDS_SUBDIR="macOS" + ;; + *) + echo "Unsupported platform: $(uname)" + exit 1 + ;; +esac + +if [ "$PRISTINE" -eq 1 ]; then + rm -rf build/${DISTRO} __Builds/${BUILDS_SUBDIR} + rm -f third-party/*.tgz third-party/*.zip +fi # Debug -cmake -S . -B build/Debug -DCMAKE_PREFIX_PATH="$(dirname "$QTBIN")" -DCMAKE_BUILD_TYPE=Debug -cmake --build build/Debug +if [ "$BUILD_DEBUG" -eq 1 ]; then + cmake -S . -B build/${DISTRO}/Debug -DCMAKE_PREFIX_PATH="$(dirname "$QTBIN")" -DCMAKE_BUILD_TYPE=Debug ${CMAKE_DISTRO_FLAG} -DBUILD_UI=${BUILD_UI} -DDEPLOY_APPS=OFF + cmake --build build/${DISTRO}/Debug --parallel ${NPROC} +fi # Release -cmake -S . -B build/Release -DCMAKE_PREFIX_PATH="$(dirname "$QTBIN")" -DCMAKE_BUILD_TYPE=Release -cmake --build build/Release +if [ "$DEPLOY" -eq 1 ]; then + DEPLOY_APPS_FLAG=ON +else + DEPLOY_APPS_FLAG=OFF +fi +cmake -S . -B build/${DISTRO}/Release -DCMAKE_PREFIX_PATH="$(dirname "$QTBIN")" -DCMAKE_BUILD_TYPE=Release ${CMAKE_DISTRO_FLAG} -DBUILD_UI=${BUILD_UI} -DDEPLOY_APPS=${DEPLOY_APPS_FLAG} +cmake --build build/${DISTRO}/Release --parallel ${NPROC} + +if [ "$INSTALL" -eq 1 ]; then + sudo cmake --install build/${DISTRO}/Release +fi echo "Check __Builds directory" diff --git a/interfaces/C++/TACDev/CMakeLists.txt b/interfaces/C++/TACDev/CMakeLists.txt index 01f1fbb..257ee5c 100644 --- a/interfaces/C++/TACDev/CMakeLists.txt +++ b/interfaces/C++/TACDev/CMakeLists.txt @@ -40,7 +40,7 @@ else() set(LIBRARY_NAME TACDev) endif() -qt_add_library(${LIBRARY_NAME} +qt_add_library(${LIBRARY_NAME} STATIC TACDev.cpp TACDev.h TACDevCore.cpp TACDevCore.h ) @@ -97,7 +97,9 @@ if(UNIX) endif() install(TARGETS ${LIBRARY_NAME} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) +install(FILES TACDev.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qtac) diff --git a/interfaces/C++/TACDev/TACDev.h b/interfaces/C++/TACDev/TACDev.h index 11a537a..d9827be 100644 --- a/interfaces/C++/TACDev/TACDev.h +++ b/interfaces/C++/TACDev/TACDev.h @@ -39,16 +39,20 @@ */ #if defined(TACDEV_LIBRARY) - #ifdef __linux__ + #if defined(_WIN32) + #define TACDEV_EXPORT __declspec(dllexport) + #elif defined(__linux__) || defined(__APPLE__) #define TACDEV_EXPORT __attribute__((visibility("default"))) #else - #define TACDEV_EXPORT __declspec(dllexport) + #error "Unsupported platform" #endif #else - #ifdef __linux__ - # define TACDEV_EXPORT __attribute__((visibility("default"))) + #if defined(_WIN32) + #define TACDEV_EXPORT __declspec(dllimport) + #elif defined(__linux__) || defined(__APPLE__) + #define TACDEV_EXPORT __attribute__((visibility("default"))) #else - # define TACDEV_EXPORT __declspec(dllimport) + #error "Unsupported platform" #endif #endif diff --git a/src/applications/CMakeLists.txt b/src/applications/CMakeLists.txt index 03f5074..1aaf4a0 100644 --- a/src/applications/CMakeLists.txt +++ b/src/applications/CMakeLists.txt @@ -41,6 +41,58 @@ find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core) qt_standard_project_setup() +option(DEPLOY_APPS "Run macdeployqt/windeployqt to create self-contained app bundles (slow)" OFF) + +if(APPLE) + # Add the Qt frameworks directory to the install rpath so apps can find Qt + # frameworks at runtime without a full macdeployqt deployment. + get_filename_component(_qt_lib_dir "${Qt6Core_DIR}/../../" ABSOLUTE) + list(APPEND CMAKE_INSTALL_RPATH "${_qt_lib_dir}") +endif() + +# Qt 6.3/6.4 use FILENAME_VARIABLE; Qt 6.5+ renamed it to OUTPUT_SCRIPT. +# On Linux, system installs use system-provided Qt shared libraries; +# running the deploy tool would copy system libs into /usr/local which is wrong. +# On Windows/macOS the deploy step is opt-in via -DDEPLOY_APPS=ON (or --deploy +# in build.sh/build.bat) to avoid slow macdeployqt/windeployqt runs during +# routine testing. +macro(qtac_deploy_app target) + if(DEPLOY_APPS AND (WIN32 OR APPLE)) + if(Qt6Core_VERSION VERSION_GREATER_EQUAL "6.5") + qt_generate_deploy_app_script( + TARGET ${target} + OUTPUT_SCRIPT deploy_script + NO_UNSUPPORTED_PLATFORM_ERROR + ) + else() + qt_generate_deploy_app_script( + TARGET ${target} + FILENAME_VARIABLE deploy_script + NO_UNSUPPORTED_PLATFORM_ERROR + ) + endif() + install(SCRIPT ${deploy_script}) + endif() +endmacro() + +if(UNIX AND NOT APPLE) + # Install a qt.conf pointing to the Qt plugins directory used at build time. + # Without this, installed binaries report an empty plugin path and fail to + # start. Works for both apt Qt (/usr/lib/.../qt6/plugins) and aqtinstall. + get_target_property(_qmake Qt6::qmake IMPORTED_LOCATION) + execute_process( + COMMAND "${_qmake}" -query QT_INSTALL_PLUGINS + OUTPUT_VARIABLE _qt_plugins_dir + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + "[Paths]\nPlugins=${_qt_plugins_dir}\n" + ) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + DESTINATION ${CMAKE_INSTALL_BINDIR} + ) +endif() + add_subdirectory(devlist) add_subdirectory(tacdump) add_subdirectory(ftdi-check) diff --git a/src/applications/device-catalog/CMakeLists.txt b/src/applications/device-catalog/CMakeLists.txt index cded440..a1b5b8f 100644 --- a/src/applications/device-catalog/CMakeLists.txt +++ b/src/applications/device-catalog/CMakeLists.txt @@ -40,7 +40,7 @@ qt_add_resources(DC_RESOURCES resources/DeviceCatalog.qrc ) -qt_add_executable(${APP_NAME} WIN32 +qt_add_executable(${APP_NAME} WIN32 MACOSX_BUNDLE DeviceCatalog.cpp DeviceCatalog.h DeviceCatalog.ui DeviceCatalogApplication.cpp DeviceCatalogApplication.h DeviceSelectionDialog.cpp DeviceSelectionDialog.h DeviceSelectionDialog.ui @@ -72,7 +72,7 @@ target_compile_definitions(${APP_NAME} PRIVATE ) target_link_directories(${APP_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_link_libraries(${APP_NAME} PRIVATE @@ -118,9 +118,4 @@ install(TARGETS ${APP_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_generate_deploy_app_script( - TARGET DeviceCatalog - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) +qtac_deploy_app(DeviceCatalog) diff --git a/src/applications/devlist/CMakeLists.txt b/src/applications/devlist/CMakeLists.txt index 8b118f1..4873e6d 100644 --- a/src/applications/devlist/CMakeLists.txt +++ b/src/applications/devlist/CMakeLists.txt @@ -52,7 +52,7 @@ target_compile_definitions(${APP_NAME} PRIVATE ) target_link_directories(${APP_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_link_libraries(${APP_NAME} PRIVATE @@ -82,9 +82,4 @@ install(TARGETS ${APP_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_generate_deploy_app_script( - TARGET ${APP_NAME} - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) +qtac_deploy_app(${APP_NAME}) diff --git a/src/applications/ftdi-check/CMakeLists.txt b/src/applications/ftdi-check/CMakeLists.txt index 02697be..9b9ab8c 100644 --- a/src/applications/ftdi-check/CMakeLists.txt +++ b/src/applications/ftdi-check/CMakeLists.txt @@ -60,7 +60,7 @@ target_compile_definitions(${APP_NAME} PRIVATE ) target_link_directories(${APP_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_link_libraries(${APP_NAME} PRIVATE @@ -112,9 +112,4 @@ install(TARGETS ${APP_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_generate_deploy_app_script( - TARGET FTDICheck - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) +qtac_deploy_app(FTDICheck) diff --git a/src/applications/programmers/lite-programmer/CMakeLists.txt b/src/applications/programmers/lite-programmer/CMakeLists.txt index 0e21133..4efe77c 100644 --- a/src/applications/programmers/lite-programmer/CMakeLists.txt +++ b/src/applications/programmers/lite-programmer/CMakeLists.txt @@ -53,7 +53,7 @@ target_compile_definitions(${APP_NAME} PRIVATE ) target_link_directories(${APP_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_link_libraries(${APP_NAME} PRIVATE @@ -85,9 +85,4 @@ install(TARGETS ${APP_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_generate_deploy_app_script( - TARGET ${APP_NAME} - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) +qtac_deploy_app(${APP_NAME}) diff --git a/src/applications/tac-configuration-editor/CMakeLists.txt b/src/applications/tac-configuration-editor/CMakeLists.txt index 662b3ee..d88bbcb 100644 --- a/src/applications/tac-configuration-editor/CMakeLists.txt +++ b/src/applications/tac-configuration-editor/CMakeLists.txt @@ -40,7 +40,7 @@ qt_add_resources(TAC_EDITOR_RESOURCES resources/TACConfigEditor.qrc ) -qt_add_executable(${APP_NAME} WIN32 +qt_add_executable(${APP_NAME} WIN32 MACOSX_BUNDLE ButtonEditor.cpp ButtonEditor.h ButtonEditor.ui CodeEditor.cpp CodeEditor.h CodeEditor.ui ConfigEditorApplication.cpp ConfigEditorApplication.h @@ -74,7 +74,7 @@ target_include_directories(${APP_NAME} PRIVATE ) target_link_directories(${APP_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_compile_definitions(${APP_NAME} PRIVATE @@ -133,8 +133,4 @@ install(TARGETS ${APP_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_generate_deploy_app_script(TARGET ${APP_NAME} - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) +qtac_deploy_app(${APP_NAME}) diff --git a/src/applications/tacdump/CMakeLists.txt b/src/applications/tacdump/CMakeLists.txt index 5e9610d..a01af35 100644 --- a/src/applications/tacdump/CMakeLists.txt +++ b/src/applications/tacdump/CMakeLists.txt @@ -45,7 +45,7 @@ target_include_directories(${APP_NAME} PRIVATE ) target_link_directories(${APP_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_compile_definitions(${APP_NAME} PRIVATE @@ -92,9 +92,4 @@ install(TARGETS ${APP_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_generate_deploy_app_script( - TARGET ${APP_NAME} - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) +qtac_deploy_app(${APP_NAME}) diff --git a/src/applications/test-automation-controller/CMakeLists.txt b/src/applications/test-automation-controller/CMakeLists.txt index 0252a7b..eefbbef 100644 --- a/src/applications/test-automation-controller/CMakeLists.txt +++ b/src/applications/test-automation-controller/CMakeLists.txt @@ -40,7 +40,7 @@ qt_add_resources(TAC_RESOURCES resources/TAC.qrc ) -qt_add_executable(${APP_NAME} WIN32 +qt_add_executable(${APP_NAME} WIN32 MACOSX_BUNDLE PreferencesDialog.cpp PreferencesDialog.h PreferencesDialog.ui TACApplication.cpp TACApplication.h TACDeviceSelection.cpp TACDeviceSelection.h TACDeviceSelection.ui @@ -65,7 +65,7 @@ target_include_directories(${APP_NAME} PRIVATE ) target_link_directories(${APP_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_compile_definitions(${APP_NAME} PRIVATE @@ -134,12 +134,7 @@ install(TARGETS TAC RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_generate_deploy_app_script( - TARGET TAC - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) +qtac_deploy_app(TAC) if(WIN32 AND WINDEPLOYQT_EXECUTABLE) add_custom_command(TARGET ${APP_NAME} POST_BUILD diff --git a/src/applications/updatedevicelist/CMakeLists.txt b/src/applications/updatedevicelist/CMakeLists.txt index d88c315..23797fe 100644 --- a/src/applications/updatedevicelist/CMakeLists.txt +++ b/src/applications/updatedevicelist/CMakeLists.txt @@ -49,7 +49,7 @@ target_include_directories(${APP_NAME} PRIVATE ) target_link_directories(${APP_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_link_libraries(${APP_NAME} PRIVATE @@ -78,9 +78,4 @@ install(TARGETS ${APP_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_generate_deploy_app_script( - TARGET ${APP_NAME} - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) +qtac_deploy_app(${APP_NAME}) diff --git a/src/applications/updatedevicelist/FTDITemplateCompiler.cpp b/src/applications/updatedevicelist/FTDITemplateCompiler.cpp index f1c0b5c..cf11495 100644 --- a/src/applications/updatedevicelist/FTDITemplateCompiler.cpp +++ b/src/applications/updatedevicelist/FTDITemplateCompiler.cpp @@ -41,6 +41,7 @@ #include "PlatformID.h" // Qt +#include #include #include #include @@ -49,22 +50,6 @@ #include #include -#ifdef Q_OS_WIN - #ifdef DEBUG - const QString xmlTemplatePath(QStringLiteral("C:\\github\\open-source\\qcom-test-automation-controller\\__Builds\\x64\\Debug\\bin\\ftdi-template.xml")); - #else - const QString xmlTemplatePath(QStringLiteral("C:\\Program Files (x86)\\Qualcomm\\QTAC\\ftdi-template.xml")); - #endif -#endif - -#ifdef Q_OS_LINUX - #ifdef DEBUG - const QString xmlTemplatePath(QStringLiteral("/local/mnt/workspace/github/open-source/qcom-test-automation-controller/__Builds/Linux/Debug/bin/ftdi-template.xml")); - #else - const QString xmlTemplatePath(QStringLiteral("/opt/qcom/QTAC/bin/ftdi-template.xml")); - #endif -#endif - const QString kUSBDescriptorPattern(QStringLiteral("%%USB_DESCRIPTOR%%")); @@ -116,6 +101,8 @@ void FTDITemplateCompiler::write() bool FTDITemplateCompiler::load() { bool result{false}; + const QString xmlTemplatePath = + QCoreApplication::applicationDirPath() + QStringLiteral("/ftdi-template.xml"); QFile xmlFile(xmlTemplatePath); if (_template.isNull() && xmlFile.open(QIODevice::ReadOnly)) diff --git a/src/applications/updatedevicelist/UpdateDeviceList.cpp b/src/applications/updatedevicelist/UpdateDeviceList.cpp index 671cb4c..201c745 100644 --- a/src/applications/updatedevicelist/UpdateDeviceList.cpp +++ b/src/applications/updatedevicelist/UpdateDeviceList.cpp @@ -53,8 +53,7 @@ #ifdef Q_OS_WIN const QString kServerConfigDir(QStringLiteral("C:\\github\\open-source\\qcom-test-automation-controller\\configurations")); -#endif -#ifdef Q_OS_LINUX +#elif defined(Q_OS_LINUX) const QString kServerConfigDir = expandPath("/local/mnt/workspace/github/open-source/qcom-test-automation-controller/configurations"); #endif @@ -191,6 +190,7 @@ void UpdateDeviceList::write() } else { +#if defined(Q_OS_WIN) || defined(Q_OS_LINUX) configFilePath = QDir::cleanPath(kServerConfigDir); if (QDir(configFilePath).exists()) @@ -205,6 +205,7 @@ void UpdateDeviceList::write() // don't print this one // std::cout << configFilePath.toLatin1().data() << " does not exist " << std::endl; } +#endif configFilePath = QDir::cleanPath(tacConfigRoot()); if (QDir(configFilePath).exists()) diff --git a/src/libraries/CMakeLists.txt b/src/libraries/CMakeLists.txt index 1ad2a12..35ba2fd 100644 --- a/src/libraries/CMakeLists.txt +++ b/src/libraries/CMakeLists.txt @@ -8,5 +8,7 @@ find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core) qt_standard_project_setup() add_subdirectory(qcommon-console) -add_subdirectory(qcommon) -add_subdirectory(ui-common) +if(BUILD_UI) + add_subdirectory(qcommon) + add_subdirectory(ui-common) +endif() diff --git a/src/libraries/qcommon-console/CMakeLists.txt b/src/libraries/qcommon-console/CMakeLists.txt index 52ae499..bcdde74 100644 --- a/src/libraries/qcommon-console/CMakeLists.txt +++ b/src/libraries/qcommon-console/CMakeLists.txt @@ -152,3 +152,9 @@ target_link_libraries(${LIBRARY_NAME} PUBLIC Qt6::Xml ftd2xx ) + +install(TARGETS ${LIBRARY_NAME} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/src/libraries/qcommon-console/Common.cmake b/src/libraries/qcommon-console/Common.cmake index 57c4f86..913b03d 100644 --- a/src/libraries/qcommon-console/Common.cmake +++ b/src/libraries/qcommon-console/Common.cmake @@ -112,6 +112,10 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(WIN32) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Zi") set(CONFIGURATION "${WINTARGET}/Debug") + elseif(APPLE) + set(CONFIGURATION "macOS/Debug") + elseif(DEFINED LINUX_DISTRO AND NOT LINUX_DISTRO STREQUAL "") + set(CONFIGURATION "Linux-${LINUX_DISTRO}/Debug") else() set(CONFIGURATION "Linux/Debug") endif() @@ -119,6 +123,10 @@ else() list(APPEND QCOMMONCONSOLE_DEFINITIONS _NDEBUG NDEBUG) if(WIN32) set(CONFIGURATION "${WINTARGET}/Release") + elseif(APPLE) + set(CONFIGURATION "macOS/Release") + elseif(DEFINED LINUX_DISTRO AND NOT LINUX_DISTRO STREQUAL "") + set(CONFIGURATION "Linux-${LINUX_DISTRO}/Release") else() set(CONFIGURATION "Linux/Release") endif() diff --git a/src/libraries/qcommon/CMakeLists.txt b/src/libraries/qcommon/CMakeLists.txt index dc6522f..5707239 100644 --- a/src/libraries/qcommon/CMakeLists.txt +++ b/src/libraries/qcommon/CMakeLists.txt @@ -78,7 +78,7 @@ target_include_directories(${LIBRARY_NAME} PUBLIC ) target_link_directories(${LIBRARY_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_compile_definitions(${LIBRARY_NAME} PUBLIC diff --git a/src/libraries/qcommon/Common.cmake b/src/libraries/qcommon/Common.cmake index e1afddb..2fcb993 100644 --- a/src/libraries/qcommon/Common.cmake +++ b/src/libraries/qcommon/Common.cmake @@ -102,6 +102,10 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") list(APPEND QCOMMON_DEFINITIONS _DEBUG DEBUG) if(WIN32) set(CONFIGURATION "${WINTARGET}/Debug") + elseif(APPLE) + set(CONFIGURATION "macOS/Debug") + elseif(DEFINED LINUX_DISTRO AND NOT LINUX_DISTRO STREQUAL "") + set(CONFIGURATION "Linux-${LINUX_DISTRO}/Debug") else() set(CONFIGURATION "Linux/Debug") endif() @@ -109,6 +113,10 @@ else() list(APPEND QCOMMON_DEFINITIONS _NDEBUG NDEBUG) if(WIN32) set(CONFIGURATION "${WINTARGET}/Release") + elseif(APPLE) + set(CONFIGURATION "macOS/Release") + elseif(DEFINED LINUX_DISTRO AND NOT LINUX_DISTRO STREQUAL "") + set(CONFIGURATION "Linux-${LINUX_DISTRO}/Release") else() set(CONFIGURATION "Linux/Release") endif() diff --git a/src/libraries/qcommon/TableCheckBox.cpp b/src/libraries/qcommon/TableCheckBox.cpp index 6d31857..4d4c348 100644 --- a/src/libraries/qcommon/TableCheckBox.cpp +++ b/src/libraries/qcommon/TableCheckBox.cpp @@ -51,7 +51,11 @@ TableCheckBox::TableCheckBox // Initialize the check-box _checkBox = new QCheckBox(this); - connect(_checkBox, &QCheckBox::checkStateChanged, this, [=, this](bool newState){ emit checkStateChanged(newState); }); +#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) + connect(_checkBox, &QCheckBox::checkStateChanged, this, [=, this](Qt::CheckState state){ emit checkStateChanged(state == Qt::Checked); }); +#else + connect(_checkBox, &QCheckBox::stateChanged, this, [=, this](int state){ emit checkStateChanged(state == Qt::Checked); }); +#endif // Prepare check box layout QHBoxLayout* layoutCheckBox = new QHBoxLayout(this); diff --git a/src/libraries/ui-common/CMakeLists.txt b/src/libraries/ui-common/CMakeLists.txt index 8e07e99..30c29a0 100644 --- a/src/libraries/ui-common/CMakeLists.txt +++ b/src/libraries/ui-common/CMakeLists.txt @@ -41,7 +41,7 @@ target_include_directories(${LIBRARY_NAME} PUBLIC ) target_link_directories(${LIBRARY_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/__Builds/x64/$/lib + ${STATIC_LIBPATH} ) target_compile_definitions(${LIBRARY_NAME} PUBLIC diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 8d948ba..e766f57 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -39,9 +39,20 @@ if(WIN32) set(FTDI_ARCHIVE "CDM-v2.12.36.20-WHQL-Certified.zip") set(DEBUG_LIB "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/lib/ftd2xx.lib") set(RELEASE_LIB "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/lib/ftd2xx.lib") +elseif(APPLE) + set(FTDI_DMG "D2XX1.4.30.dmg") + set(FTDI_URL "https://ftdichip.com/wp-content/uploads/2024/04/${FTDI_DMG}") + set(FTDI_ARCHIVE "${FTDI_DMG}") + set(DEBUG_LIB "${CMAKE_SOURCE_DIR}/__Builds/macOS/Debug/lib/libftd2xx.a") + set(RELEASE_LIB "${CMAKE_SOURCE_DIR}/__Builds/macOS/Release/lib/libftd2xx.a") else() - set(FTDI_URL "https://ftdichip.com/wp-content/uploads/2025/03/libftd2xx-linux-x86_64-1.4.33.tgz") - set(FTDI_ARCHIVE "libftd2xx-linux-x86_64-1.4.33.tgz") + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64") + set(FTDI_URL "https://ftdichip.com/wp-content/uploads/2025/03/libftd2xx-linux-arm-v8-1.4.33.tgz") + set(FTDI_ARCHIVE "libftd2xx-linux-arm-v8-1.4.33.tgz") + else() + set(FTDI_URL "https://ftdichip.com/wp-content/uploads/2025/03/libftd2xx-linux-x86_64-1.4.33.tgz") + set(FTDI_ARCHIVE "libftd2xx-linux-x86_64-1.4.33.tgz") + endif() set(DEBUG_LIB "${CMAKE_SOURCE_DIR}/__Builds/Linux/Debug/lib/libftd2xx.a") set(RELEASE_LIB "${CMAKE_SOURCE_DIR}/__Builds/Linux/Release/lib/libftd2xx.a") endif() @@ -55,63 +66,95 @@ if(NOT EXISTS "${DEBUG_LIB}" OR NOT EXISTS "${RELEASE_LIB}") endif() if(NEED_DOWNLOAD) - set(RETRY_COUNT 0) - while(RETRY_COUNT LESS 3) - math(EXPR RETRY_COUNT "${RETRY_COUNT} + 1") - if(EXISTS "${ARCHIVE_PATH}") - file(REMOVE "${ARCHIVE_PATH}") - endif() - file(DOWNLOAD "${FTDI_URL}" "${ARCHIVE_PATH}" SHOW_PROGRESS STATUS DOWNLOAD_STATUS TIMEOUT 300) - list(GET DOWNLOAD_STATUS 0 DOWNLOAD_ERROR_CODE) - if(DOWNLOAD_ERROR_CODE EQUAL 0 AND EXISTS "${ARCHIVE_PATH}") - execute_process(COMMAND ${CMAKE_COMMAND} -E tar tf "${ARCHIVE_PATH}" RESULT_VARIABLE TAR_RESULT OUTPUT_QUIET ERROR_QUIET) - if(TAR_RESULT EQUAL 0) - break() + if(APPLE) + if(NOT EXISTS "${ARCHIVE_PATH}") + file(DOWNLOAD "${FTDI_URL}" "${ARCHIVE_PATH}" SHOW_PROGRESS STATUS DOWNLOAD_STATUS TIMEOUT 300) + list(GET DOWNLOAD_STATUS 0 DOWNLOAD_ERROR_CODE) + if(NOT DOWNLOAD_ERROR_CODE EQUAL 0 OR NOT EXISTS "${ARCHIVE_PATH}") + message(FATAL_ERROR "Failed to download FTDI D2XX for macOS from ${FTDI_URL}") endif() endif() - if(RETRY_COUNT LESS 3) - execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 5) + else() + set(RETRY_COUNT 0) + while(RETRY_COUNT LESS 3) + math(EXPR RETRY_COUNT "${RETRY_COUNT} + 1") + if(EXISTS "${ARCHIVE_PATH}") + file(REMOVE "${ARCHIVE_PATH}") + endif() + file(DOWNLOAD "${FTDI_URL}" "${ARCHIVE_PATH}" SHOW_PROGRESS STATUS DOWNLOAD_STATUS TIMEOUT 300) + list(GET DOWNLOAD_STATUS 0 DOWNLOAD_ERROR_CODE) + if(DOWNLOAD_ERROR_CODE EQUAL 0 AND EXISTS "${ARCHIVE_PATH}") + execute_process(COMMAND ${CMAKE_COMMAND} -E tar tf "${ARCHIVE_PATH}" RESULT_VARIABLE TAR_RESULT OUTPUT_QUIET ERROR_QUIET) + if(TAR_RESULT EQUAL 0) + break() + endif() + endif() + if(RETRY_COUNT LESS 3) + execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 5) + endif() + endwhile() + if(RETRY_COUNT EQUAL 3) + message(FATAL_ERROR "Failed to download FTDI library after 3 attempts") endif() - endwhile() - if(RETRY_COUNT EQUAL 3) - message(FATAL_ERROR "Failed to download FTDI library after 3 attempts") endif() - file(REMOVE_RECURSE "${TEMP_DIR}") - file(MAKE_DIRECTORY "${TEMP_DIR}") - execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf "${ARCHIVE_PATH}" WORKING_DIRECTORY "${TEMP_DIR}") - - if(WIN32) - file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/lib") - file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/lib") - file(GLOB SOURCE_LIB "${TEMP_DIR}/amd64/ftd2xx.lib") - - file(GLOB SOURCE_DLL "${TEMP_DIR}/amd64/FTD2XX64.dll") - if(SOURCE_DLL) - file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/bin") - file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/bin") - file(COPY "${SOURCE_DLL}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/bin") - file(RENAME "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/bin/FTD2XX64.dll" "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/bin/ftd2xx.dll") - file(COPY "${SOURCE_DLL}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/bin") - file(RENAME "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/bin/FTD2XX64.dll" "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/bin/ftd2xx.dll") + if(APPLE) + file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/macOS/Debug/lib") + file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/macOS/Release/lib") + execute_process( + COMMAND hdiutil attach -readonly -nobrowse "${ARCHIVE_PATH}" + OUTPUT_VARIABLE HDIUTIL_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "/Volumes/[^\n\t ]*" MOUNT_POINT "${HDIUTIL_OUTPUT}") + string(STRIP "${MOUNT_POINT}" MOUNT_POINT) + execute_process( + COMMAND find "${MOUNT_POINT}" -name "libftd2xx.a" + OUTPUT_VARIABLE MACOS_LIB OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT MACOS_LIB) + message(FATAL_ERROR "libftd2xx.a not found in FTDI DMG at ${MOUNT_POINT}") endif() + execute_process(COMMAND "${CMAKE_COMMAND}" -E copy "${MACOS_LIB}" "${DEBUG_LIB}") + execute_process(COMMAND "${CMAKE_COMMAND}" -E copy "${MACOS_LIB}" "${RELEASE_LIB}") + execute_process(COMMAND hdiutil detach "${MOUNT_POINT}") + else() + file(REMOVE_RECURSE "${TEMP_DIR}") + file(MAKE_DIRECTORY "${TEMP_DIR}") + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf "${ARCHIVE_PATH}" WORKING_DIRECTORY "${TEMP_DIR}") - if(NOT SOURCE_LIB) - file(GLOB SOURCE_LIB "${TEMP_DIR}/Static/amd64/ftd2xx.lib") + if(WIN32) + file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/lib") + file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/lib") + file(GLOB SOURCE_LIB "${TEMP_DIR}/amd64/ftd2xx.lib") + + file(GLOB SOURCE_DLL "${TEMP_DIR}/amd64/FTD2XX64.dll") + if(SOURCE_DLL) + file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/bin") + file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/bin") + file(COPY "${SOURCE_DLL}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/bin") + file(RENAME "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/bin/FTD2XX64.dll" "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/bin/ftd2xx.dll") + file(COPY "${SOURCE_DLL}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/bin") + file(RENAME "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/bin/FTD2XX64.dll" "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/bin/ftd2xx.dll") + endif() + + if(NOT SOURCE_LIB) + file(GLOB SOURCE_LIB "${TEMP_DIR}/Static/amd64/ftd2xx.lib") + endif() + file(COPY "${SOURCE_LIB}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/lib") + file(COPY "${SOURCE_LIB}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/lib") + else() + file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/Linux/Debug/lib") + file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/Linux/Release/lib") + file(GLOB_RECURSE SOURCE_LIB "${TEMP_DIR}/libftd2xx-static.a") + if(NOT SOURCE_LIB) + message(FATAL_ERROR "libftd2xx-static.a not found in downloaded FTDI archive") + endif() + file(COPY "${SOURCE_LIB}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/Linux/Debug/lib") + file(COPY "${SOURCE_LIB}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/Linux/Release/lib") + file(RENAME "${CMAKE_SOURCE_DIR}/__Builds/Linux/Debug/lib/libftd2xx-static.a" "${DEBUG_LIB}") + file(RENAME "${CMAKE_SOURCE_DIR}/__Builds/Linux/Release/lib/libftd2xx-static.a" "${RELEASE_LIB}") endif() - file(COPY "${SOURCE_LIB}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/x64/Debug/lib") - file(COPY "${SOURCE_LIB}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/x64/Release/lib") - else() - file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/Linux/Debug/lib") - file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/__Builds/Linux/Release/lib") - file(GLOB SOURCE_LIB "${TEMP_DIR}/*/libftd2xx-static.a") - file(COPY "${SOURCE_LIB}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/Linux/Debug/lib") - file(COPY "${SOURCE_LIB}" DESTINATION "${CMAKE_SOURCE_DIR}/__Builds/Linux/Release/lib") - file(RENAME "${CMAKE_SOURCE_DIR}/__Builds/Linux/Debug/lib/libftd2xx-static.a" "${DEBUG_LIB}") - file(RENAME "${CMAKE_SOURCE_DIR}/__Builds/Linux/Release/lib/libftd2xx-static.a" "${RELEASE_LIB}") + + file(REMOVE_RECURSE "${TEMP_DIR}") endif() - - file(REMOVE_RECURSE "${TEMP_DIR}") endif() if(WIN32) @@ -126,6 +169,10 @@ else() IMPORTED_LOCATION_RELEASE "${RELEASE_LIB}" IMPORTED_LOCATION "${RELEASE_LIB}" ) + if(APPLE) + set_target_properties(ftd2xx PROPERTIES + INTERFACE_LINK_LIBRARIES "-framework CoreFoundation;-framework IOKit") + endif() endif() if(WIN32 AND DEFINED ENV{QTDIR}) @@ -158,9 +205,13 @@ if(WIN32 AND DEFINED ENV{QTDIR}) endif() endif() +install(FILES "${RELEASE_LIB}" DESTINATION ${CMAKE_INSTALL_LIBDIR}) + function(link_ftd2xx target_name) if(WIN32) target_link_libraries(${target_name} PRIVATE $<$:ftd2xx_debug> $<$:ftd2xx_release>) + elseif(APPLE) + target_link_libraries(${target_name} PRIVATE ftd2xx) else() target_link_libraries(${target_name} PRIVATE ftd2xx pthread dl) endif()