diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 66d1ce460..5ec8fe325 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,14 +8,6 @@ on: schedule: - cron: 1 12 * * 1 -env: - WIN_LIBUSB_INC: -DLIBUSB_INCLUDE_DIR=C:/vcpkg/installed/x64-windows/include/libusb-1.0 - WIN_LIBUSB_LIB: -DLIBUSB_LIBRARIES=C:/vcpkg/installed/x64-windows/lib/libusb-1.0.lib - WIN_FFTW_INC: -DFFTW_INCLUDES=C:/vcpkg/installed/x64-windows/include - WIN_FFTW_LIB: -DFFTW_LIBRARIES=C:/vcpkg/installed/x64-windows/lib/fftw3f.lib - WIN_PTHREAD_INC: -DTHREADS_PTHREADS_INCLUDE_DIR=C:/vcpkg/installed/x64-windows/include - WIN_PTHREAD_LIB: -DTHREADS_PTHREADS_WIN32_LIBRARY=C:/vcpkg/installed/x64-windows/lib/pthreadvc3.lib - jobs: host: strategy: @@ -53,7 +45,7 @@ jobs: - name: Configure CMake (Windows) working-directory: ${{runner.workspace}}/host/build - run: cmake $env:GITHUB_WORKSPACE/host/ $env:WIN_LIBUSB_INC $env:WIN_LIBUSB_LIB $env:WIN_FFTW_INC $env:WIN_FFTW_LIB $env:WIN_PTHREAD_INC $env:WIN_PTHREAD_LIB + run: cmake $env:GITHUB_WORKSPACE/host/ -DCMAKE_PREFIX_PATH=C:/vcpkg/installed/x64-windows/ if: matrix.os == 'windows-latest' - name: Build @@ -70,7 +62,7 @@ jobs: - name: Configure CMake (libhackrf, Windows) working-directory: ${{runner.workspace}}/host/libhackrf/build - run: cmake $env:GITHUB_WORKSPACE/host/libhackrf/ $env:WIN_LIBUSB_INC $env:WIN_LIBUSB_LIB $env:WIN_PTHREAD_INC $env:WIN_PTHREAD_LIB + run: cmake $env:GITHUB_WORKSPACE/host/libhackrf/ -DCMAKE_PREFIX_PATH=C:/vcpkg/installed/x64-windows/ -DCMAKE_INSTALL_PREFIX=${{runner.workspace}}/install if: matrix.os == 'windows-latest' - name: Build (libhackrf) @@ -86,7 +78,7 @@ jobs: - name: Install (libhackrf, Windows) working-directory: ${{runner.workspace}}/host/libhackrf/build run: | - cmake --install . --config Release --prefix=$env:GITHUB_WORKSPACE/install + cmake --install . --config Release if: matrix.os == 'windows-latest' - name: Create Build Environment (hackrf-tools) @@ -100,7 +92,7 @@ jobs: - name: Configure CMake (hackrf-tools, Windows) working-directory: ${{runner.workspace}}/host/hackrf-tools/build run: | - cmake $env:GITHUB_WORKSPACE/host/hackrf-tools/ $env:WIN_FFTW_INC $env:WIN_FFTW_LIB -DLIBHACKRF_INCLUDE_DIR=$env:GITHUB_WORKSPACE/install/include/libhackrf -DLIBHACKRF_LIBRARIES=$env:GITHUB_WORKSPACE/install/bin/hackrf.lib + cmake $env:GITHUB_WORKSPACE/host/hackrf-tools/ -DCMAKE_PREFIX_PATH=C:/vcpkg/installed/x64-windows/ -DLIBHACKRF_INCLUDE_DIR=${{runner.workspace}}/install/include/libhackrf -DLIBHACKRF_LIBRARY=${{runner.workspace}}/install/lib/hackrf.lib if: matrix.os == 'windows-latest' - name: Build (hackrf-tools) diff --git a/appveyor.yml b/appveyor.yml index d8d99e9ef..296c9e517 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,6 +18,7 @@ install: - curl -fsS -o "C:\fftw-3.3.5.zip" "ftp://ftp.fftw.org/pub/fftw/fftw-3.3.5-dll64.zip" - 7z x -y "C:\fftw-3.3.5.zip" -o"C:\fftw" - cd c:\fftw + - ps: lib /machine:x64 /def:libfftw3-3.def - ps: lib /machine:x64 /def:libfftw3f-3.def # ARM GCC for firmware builds # - appveyor DownloadFile "https://developer.arm.com/-/media/Files/downloads/gnu-rm/6-2017q2/gcc-arm-none-eabi-6-2017-q2-update-win32.zip" -FileName "C:\gcc-arm-none-eabi-win32.zip" @@ -34,8 +35,9 @@ build_script: -DTHREADS_PTHREADS_INCLUDE_DIR=c:\pthreads\Pre-built.2\include \ -DTHREADS_PTHREADS_WIN32_LIBRARY=c:\pthreads\Pre-built.2\lib\x64\pthreadVC2.lib \ -DPKG_CONFIG_EXECUTABLE="C:\pkg-config\bin\pkg-config.exe" \ - -DFFTW_INCLUDES=C:\fftw \ - -DFFTW_LIBRARIES=C:\fftw\libfftw3f-3.lib \ + -DFFTW_INCLUDES_SERIAL=C:\fftw \ + -DFFTW_LIBRARY_SERIAL=C:\fftw\libfftw3-3.lib \ + -DFFTWF_LIBRARY_SERIAL=C:\fftw\libfftw3f-3.lib \ .. - msbuild HackRF.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" # Firmware diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 72cbfb492..b13acbdd4 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -1,23 +1,17 @@ #top dir cmake project for libhackrf + tools -cmake_minimum_required(VERSION 2.8) -project (HackRF C) +cmake_minimum_required(VERSION 3.8) +project(HackRF LANGUAGES C) -set(CMAKE_C_FLAGS "$ENV{CFLAGS}" CACHE STRING "C Flags") +# standard policies for CMake 3.8 +cmake_policy(VERSION 3.8) +# Run common init code +# ----------------------------------------------------- +include(cmake/hackrf-host.cmake) + +# Subdirectories +# ----------------------------------------------------- add_subdirectory(libhackrf) add_subdirectory(hackrf-tools) -######################################################################## -# Create uninstall target -######################################################################## - -configure_file( - ${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake -@ONLY) - - -add_custom_target(uninstall - ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake -) diff --git a/host/README.md b/host/README.md index f2fb47852..96e9ca2a0 100644 --- a/host/README.md +++ b/host/README.md @@ -33,11 +33,17 @@ rm -rf * ## How to build host software on Windows: ### Prerequisites for Cygwin, MinGW, or Visual Studio: -* cmake-2.8.12.1 or later from http://www.cmake.org/cmake/resources/software.html -* libusbx-1.0.18 or later from http://sourceforge.net/projects/libusbx/files/latest/download?source=files -* fftw-3.3.5 or later from http://www.fftw.org/install/windows.html +You will need to install these tools: +* cmake-3.8 or later from http://www.cmake.org/cmake/resources/software.html * Install Windows driver for HackRF hardware or use Zadig see http://sourceforge.net/projects/libwdi/files/zadig - If you want to use Zadig select HackRF USB device and just install/replace it with WinUSB driver. + +You will also need these dependency libraries: +* libusb-1.0.18 or later from https://libusb.info/ + * Make sure to grab the binaries corresponding to your VS version from the zip file +* fftw-3.3.5 or later from http://www.fftw.org/install/windows.html + +If your environment has a package manager, such as Cygwin or MSYS2, you should be able to install these from there. Otherwise, you can download binaries directly from these sites and copy them to a build dependencies prefix. DLLs go in the bin folder, headers in include, .dll.a and .lib files in the lib folder, like normal. >**Note for Windows build:** You shall always execute hackrf-tools from Windows command shell and not from Cygwin or MinGW shell because on Cygwin/MinGW @@ -53,26 +59,39 @@ make install ``` ### For MinGW: + +If you downloaded the fftw3 binaries above, you have to turn that fftw3 DLL into something MinGW can link to by running these commands in your prefix bin folder: +``` +C:\your\build\prefix\bin> dlltool -d libfftw3f-3.def -l libfftw3f-3.dll.a -D libfftw3f-3.dll +C:\your\build\prefix\bin> dlltool -d libfftw3-3.def -l libfftw3-3.dll.a -D libfftw3-3.dll +``` + +Then move the generated .dll.a files to your prefix lib folder. + +Now you can build from a Windows command prompt: ``` mkdir host/build cd host/build -cmake ../ -G "MSYS Makefiles" -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ -make -make install +cmake ../ -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=C:/your/build/prefix -DCMAKE_INSTALL_PREFIX=C:/your/install/prefix +mingw32-make +mingw32-make install ``` ### For Visual Studio 2015 x64 -Create library definition for MSVC to link to -`C:\fftw-3.3.5-dll64> lib /machine:x64 /def:libfftw3f-3.def` + +Similarly to the MinGW instructions, create fftw3 import libraries for MSVC to link to. You may have to run these from a Visual Studio command prompt in the folder where you extracted the fftw3 .dll and .def files: +``` +C:\your\build\prefix\bin> lib /machine:x64 /def:libfftw3f-3.def +C:\your\build\prefix\bin> lib /machine:x64 /def:libfftw3-3.def +``` +Then move the generated .lib files to your prefix lib folder. Also rename them to get rid of the "lib" prefix, e.g. `fftw3-3.lib`. + +For libusb, libusb-1.0.dll needs to be extracted to your bin folder, libusb-1.0.lib needs to be extracted to your lib folder and renamed usb-1.0.lib, and the libusb-1.0/ folder needs to be extracted to your include folder. + +For MSVC you will also need one additional dependency, [pthreads-win32](http://mirrors.kernel.org/sourceware/pthreads-win32/pthreads-w32-2-9-1-release.zip). Download that and extract the headers and `pthreadVC2.lib` from the prebuilts folder inside the zip. ``` -c:\hackrf\host\build> cmake ../ -G "Visual Studio 14 2015 Win64" \ --DLIBUSB_INCLUDE_DIR=c:\libusb-1.0.21\libusb \ --DLIBUSB_LIBRARIES=c:\libusb-1.0.21\MS64\dll\lib\libusb-1.0.lib \ --DTHREADS_PTHREADS_INCLUDE_DIR=c:\pthreads-w32-2-9-1-release\Pre-built.2\include \ --DTHREADS_PTHREADS_WIN32_LIBRARY=c:\pthreads-w32-2-9-1-release\Pre-built.2\lib\x64\pthreadVC2.lib \ --DFFTW_INCLUDES=C:\fftw-3.3.5-dll64 \ --DFFTW_LIBRARIES=C:\fftw-3.3.5-dll64\libfftw3f-3.lib +c:\hackrf\host\build> cmake ../ -G "Visual Studio 14 2015 Win64" -DCMAKE_PREFIX_PATH=C:/your/build/prefix -DCMAKE_INSTALL_PREFIX=C:/your/install/prefix ``` CMake will produce a solution file named `HackRF.sln` and a series of diff --git a/host/cmake/hackrf-host.cmake b/host/cmake/hackrf-host.cmake new file mode 100644 index 000000000..2e35fcc86 --- /dev/null +++ b/host/cmake/hackrf-host.cmake @@ -0,0 +1,104 @@ +# This script contains the top-level logic for initializing the hackrf host +# software build system. Whichever directory CMake is from calls this +# CMake script to do all needed setup. + +list(APPEND CMAKE_MODULE_PATH + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/modules + ${CMAKE_CURRENT_LIST_DIR}/modules/amber-cmake) + +include(TryLinkLibrary) +include(LibraryUtils) + +set(HACKRF_HOST_INCLUDED TRUE) + +# Compilation flags +# ----------------------------------------------------- + +if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + + set(CMAKE_C_FLAGS_RELEASE "-O3") + set(CMAKE_C_FLAGS_DEBUG "-g3 -O0") + set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + +elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + + set(CMAKE_C_FLAGS_RELEASE "/O2") + set(CMAKE_C_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od") + set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} /W3") + + # disable verbose security warnings + add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) + + # enable M_PI + add_definitions(-D_USE_MATH_DEFINES=1) + + # disable deprecated API headers + add_definitions(-DWIN32_LEAN_AND_MEAN) + +elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + + set(CMAKE_C_FLAGS_RELEASE "-O3") + set(CMAKE_C_FLAGS_DEBUG "-g3 -O0") + set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +else() + + message(WARNING "Unknown compiler ${CMAKE_C_COMPILER_ID}, don't know how to set CFLAGS") +endif() + +# language standard +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_EXTENSIONS TRUE) # for M_PI + +# endianness +include(TestBigEndian) +test_big_endian(BIGENDIAN) +if(BIGENDIAN) + add_definitions(-DHACKRF_BIG_ENDIAN) +endif() + +# RPATH +# (set to point to lib dir in install prefix) +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# Find dependencies +# ----------------------------------------------------- +message(STATUS "Checking dependencies...") + +# libusb1.0 +find_package(USB1 REQUIRED) +import_library(libusb ${LIBUSB_LIBRARIES} ${LIBUSB_INCLUDE_DIR}) + +# pthread +if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + # tell FindThreads to use MSVC pthread library + set(THREADS_USE_PTHREADS_WIN32 TRUE) +endif() +find_package(Threads REQUIRED) + +if(EXISTS "${THREADS_PTHREADS_INCLUDE_DIR}") + import_libraries(pthread LIBRARIES ${CMAKE_THREAD_LIBS_INIT} INCLUDES ${THREADS_PTHREADS_INCLUDE_DIR}) +else() + # no include dir + import_libraries(pthread LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) +endif() + +# Options +# ----------------------------------------------------- +set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX") + + +######################################################################## +# Create uninstall target +######################################################################## + +configure_file( + ${CMAKE_CURRENT_LIST_DIR}/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +@ONLY) + + +add_custom_target(uninstall + ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +) diff --git a/host/cmake/modules/FindFFTW.cmake b/host/cmake/modules/FindFFTW.cmake index 802db4f5b..c1d8ecb94 100644 --- a/host/cmake/modules/FindFFTW.cmake +++ b/host/cmake/modules/FindFFTW.cmake @@ -1,30 +1,368 @@ # - Find FFTW # Find the native FFTW includes and library +# Components: +# MPI Fortran SinglePrecision QuadPrecision +# FFTW_COMPILE_OPTIONS - Compile options to apply when using fftw +# FFTW_INCLUDES - where to find fftw3.h +# FFTW_LIBRARIES - List of libraries when using FFTW. +# FFTW_FOUND - True if FFTW found. +# FFTW_IS_SHARED - True if FFTW is being linked as a shared library +# FFTW__FOUND - Whether the given component was found. # -# FFTW_INCLUDES - where to find fftw3.h -# FFTW_LIBRARIES - List of libraries when using FFTW. -# FFTW_FOUND - True if FFTW found. +# Note that FFTW splits itself into multiple libraries, +# single precision (fftwf), double precision (fftw), and quad precision (fftwl). +# By default FindFFTW will find only the standard double precision variant. +# To guarantee that you get the other variants, request the relevant components. +# +# Why is there a "Fortran" component you ask? It's because some systems lack the Fortran headers (e.g. fftw3.f03) +# +# when using components: +# FFTW_INCLUDES_SERIAL - include path for FFTW serial +# FFTW_LIBRARIES_SERIAL - library for use of fftw from C and Fortran +# FFTW_INCLUDES_MPI - include path for FFTW MPI +# FFTW_LIBRARIES_MPI - extra FFTW library to use MPI +# +# This module also creates the following imported targets, if the relevant components are enabled: +# fftw::fftwl - Main (double precision) library +# fftw::fftwf - Single precision library +# fftw::fftwq - Quad precision library +# fftw::mpi_f - MPI single precision library +# fftw::mpi_l - MPI double precision library +# fftw::mpi_q - MPI quad precision library +# fftw::fftw - All enabled libraries -if (FFTW_INCLUDES) +if (FFTW_FOUND) # Already in cache, be silent set (FFTW_FIND_QUIETLY TRUE) -endif (FFTW_INCLUDES) +endif() + +include(CheckCSourceCompiles) + +set(FFTW_REQUIRED_VARIABLES ) +set(FFTW_COMPILE_OPTIONS ) + +set(FIND_FFTW_DEBUG FALSE) + +# utility function for finding multiple precisions +macro(fftw_find_precision COMPONENT PREC LIBNAMES CHECK_FUNCTION TYPE) + + if(FIND_FFTW_DEBUG) + message("Searching for split ${TYPE} FFTW library (${COMPONENT}) with names ${LIBNAMES}") + endif() + + # first find the library + find_library(FFTW${PREC}_LIBRARY_${TYPE} NAMES ${LIBNAMES}) + + if(EXISTS "${FFTW${PREC}_LIBRARY_${TYPE}}") + + if(FIND_FFTW_DEBUG) + message("Found ${COMPONENT} ${TYPE} FFTW library: ${FFTW${PREC}_LIBRARY_${TYPE}}") + endif() + + # now check if it works + set(LIBS_TO_CHECK ${FFTW${PREC}_LIBRARY_${TYPE}}) + + if("${TYPE}" STREQUAL "SERIAL") + # only link serial FFTW + list(APPEND LIBS_TO_CHECK ${FFTW_LIBRARY_SERIAL}) + else() + # link serial and parallel + list(APPEND LIBS_TO_CHECK ${FFTW_LIBRARY_MPI} ${FFTW_LIBRARY_SERIAL}) + endif() + + fftw_check_c_function(${CHECK_FUNCTION} FFTW${PREC}_${TYPE}_WORKS ${LIBS_TO_CHECK}) + + unset(LIBS_TO_CHECK) + + else() + if(FIND_FFTW_DEBUG) + message("Could not find ${COMPONENT} ${TYPE} FFTW library: ${FFTW${PREC}_LIBRARY_${TYPE}}") + endif() + + set(FFTW${PREC}_${TYPE}_WORKS FALSE) + endif() + + if(FFTW${PREC}_${TYPE}_WORKS) + set(FFTW_LIBRARIES ${FFTW${PREC}_LIBRARY_SERIAL} ${FFTW_LIBRARIES}) + set(FFTW_LIBRARIES_${TYPE} ${FFTW${PREC}_LIBRARY_SERIAL} ${FFTW_LIBRARIES_${TYPE}}) + + # if the component is already set to not found, then don't make it found + if(NOT (DEFINED FFTW_${COMPONENT}_FOUND AND NOT FFTW_${COMPONENT}_FOUND)) + set(FFTW_${COMPONENT}_FOUND TRUE) + endif() + endif() + + if(FFTW_FIND_REQUIRED_${COMPONENT}) + list(APPEND FFTW_REQUIRED_VARIABLES FFTW${PREC}_LIBRARY_${TYPE} FFTW${PREC}_${TYPE}_WORKS) + endif() + +endmacro(fftw_find_precision) + +# Check if a given function can be found in a given library. +# Similar to CheckFunctionExists, but can handle DLL imports on Windows. +function(fftw_check_c_function FUNCTION RESULT_VARIABLE) # ARGN: LIBRARIES... + + # mirror the logic in fftw3.h + if(FFTW_DLL_IMPORT) + set(FUNCTION_PREFIX "extern __declspec(dllimport)") + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(FUNCTION_PREFIX "extern") + else() + set(FUNCTION_PREFIX "") + endif() + + try_link_library(${RESULT_VARIABLE} + LANGUAGE C + FUNCTION ${FUNCTION} + FUNC_PREFIX ${FUNCTION_PREFIX} + LIBRARIES ${ARGN}) + +endfunction(fftw_check_c_function) + +# headers +# -------------------------------------------------------------------- + +find_path (FFTW_INCLUDES_SERIAL fftw3.h) + +set(FFTW_INCLUDES ${FFTW_INCLUDES_SERIAL}) +list(APPEND FFTW_REQUIRED_VARIABLES FFTW_INCLUDES_SERIAL) + +# serial libraries +# -------------------------------------------------------------------- + +find_library(FFTW_LIBRARY_SERIAL NAMES fftw3-3 fftw3 fftw) +set(FFTW_LIBRARIES ${FFTW_LIBRARY_SERIAL}) +set(FFTW_LIBRARIES_SERIAL ${FFTW_LIBRARY_SERIAL}) + +if(FIND_FFTW_DEBUG AND EXISTS "${FFTW_LIBRARY_SERIAL}") + message("Found main FFTW library: ${FFTW_LIBRARY_SERIAL}") +endif() + +# set up DLL compile flags (need to check type of library) +set(FFTW_IS_SHARED FALSE) +set(FFTW_DLL_IMPORT FALSE) +if(EXISTS "${FFTW_LIBRARY_SERIAL}") + get_lib_type(${FFTW_LIBRARY_SERIAL} FFTW_LIB_TYPE) + + if(FIND_FFTW_DEBUG) + message("Lib type: ${FFTW_LIB_TYPE}") + endif() + + if(FFTW_LIB_TYPE STREQUAL "SHARED" OR FFTW_LIB_TYPE STREQUAL "IMPORT") + set(FFTW_IS_SHARED TRUE) + endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND FFTW_LIB_TYPE STREQUAL "IMPORT") + set(FFTW_DLL_IMPORT TRUE) + set(FFTW_COMPILE_OPTIONS -DFFTW_DLL) + endif() + +endif() -find_path (FFTW_INCLUDES fftw3.h) -IF (WIN32) -include_directories(${FFTW_INCLUDES}) -find_library (FFTW_LIBRARIES NAMES ${FFTW_LIBRARIES}) -ELSE(WIN32) -find_library (FFTW_LIBRARIES NAMES fftw3f) -ENDIF(WIN32) +if(EXISTS "${FFTW_LIBRARY_SERIAL}") + fftw_check_c_function(fftw_execute FFTW_WORKS ${FFTW_LIBRARY_SERIAL}) +else() + set(FFTW_WORKS FALSE) +endif() +set(FFTW_REQUIRED_VARIABLES FFTW_LIBRARY_SERIAL FFTW_WORKS ${FFTW_REQUIRED_VARIABLES}) +# search for precision libraries +if("${FFTW_FIND_COMPONENTS}" MATCHES "SinglePrecision") + fftw_find_precision(SinglePrecision F "fftw3f-3;fftw3f;fftwf" fftwf_execute SERIAL) +endif() +if("${FFTW_FIND_COMPONENTS}" MATCHES "QuadPrecision") + fftw_find_precision(QuadPrecision L "fftw3l-3;fftw3l;fftwl" fftwl_execute SERIAL) +endif() + +# Fortran component +# -------------------------------------------------------------------- + +if("${FFTW_FIND_COMPONENTS}" MATCHES "Fortran") + + # should exist if Fortran support is present + set(FFTW_FORTRAN_HEADER "${FFTW_INCLUDES_SERIAL}/fftw3.f03") + + if(NOT EXISTS "${FFTW_INCLUDES_SERIAL}") + message(STATUS "Cannot search for FFTW Fortran headers because the serial headers were not found") + set(FFTW_Fortran_FOUND FALSE) + elseif(EXISTS "${FFTW_FORTRAN_HEADER}") + + # check that the Fortran compiler can link fftw and that the manglings match + + # Deal with annoying issue: sometimes /usr/include is removed from Fortran + # include directories since CMake incorrectly thinks it's part of the implcit + # include directories. + # We could try clearing "CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES" but that won't + # work in try_link_library(). + set(FFTW_INCLUDES_FORTRAN ${FFTW_INCLUDES_SERIAL}) + if("${FFTW_INCLUDES_FORTRAN}" IN_LIST CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES) + get_filename_component(FFTW_FORTRAN_INCLUDE_FOLDER ${FFTW_INCLUDES_FORTRAN} NAME ) + set(FFTW_INCLUDES_FORTRAN ${FFTW_INCLUDES_FORTRAN}/../${FFTW_FORTRAN_INCLUDE_FOLDER}) + endif() + + try_link_library(FFTW_FORTRAN_WORKS + LANGUAGE Fortran + FUNCTION fftw_cleanup + LIBRARIES ${FFTW_LIBRARY_SERIAL} + INCLUDES ${FFTW_INCLUDES_FORTRAN} + FUNC_CALL " + use, intrinsic :: iso_c_binding + implicit none + include 'fftw3.f03' + call fftw_cleanup()") + + if(FFTW_FORTRAN_WORKS) + set(FFTW_Fortran_FOUND TRUE) + list(APPEND FFTW_INCLUDES ${FFTW_INCLUDES_FORTRAN}) + else() + set(FFTW_Fortran_FOUND FALSE) + endif() + else() + set(FFTW_Fortran_FOUND FALSE) + message(STATUS "Cannot find FFTW Fortran headers - ${FFTW_FORTRAN_HEADER} is missing.") + endif() + + if(FFTW_FIND_REQUIRED_Fortran) + list(APPEND FFTW_REQUIRED_VARIABLES FFTW_FORTRAN_HEADER FFTW_FORTRAN_WORKS) + endif() + +endif() + +# MPI component +# -------------------------------------------------------------------- +if("${FFTW_FIND_COMPONENTS}" MATCHES "MPI") + find_library(FFTW_LIBRARY_MPI NAMES fftw3_mpi fftw_mpi) + set(FFTW_LIBRARIES_MPI ${FFTW_LIBRARY_MPI}) + + find_path(FFTW_INCLUDES_MPI fftw3-mpi.h) + list(APPEND FFTW_INCLUDES ${FFTW_INCLUDES_MPI}) + + set(CMAKE_REQUIRED_LIBRARIES ${FFTW_LIBRARY_MPI}) + if(EXISTS "${FFTW_LIBRARY_MPI}") + fftw_check_c_function(fftw_mpi_init FFTW_MPI_WORKS) + else() + set(FFTW_MPI_WORKS FALSE) + endif() + + if(FFTW_MPI_WORKS) + set(FFTW_MPI_FOUND TRUE) + endif() + + if(FFTW_FIND_REQUIRED_MPI) + list(APPEND FFTW_REQUIRED_VARIABLES FFTW_LIBRARY_MPI FFTW_INCLUDES_MPI FFTW_MPI_WORKS) + endif() + + if("${FFTW_FIND_COMPONENTS}" MATCHES "SinglePrecision") + fftw_find_precision(SinglePrecision F "fftw3f_mpi-3;fftw3f_mpi;fftwf_mpi" fftwl_mpi_init MPI) + endif() + + if("${FFTW_FIND_COMPONENTS}" MATCHES "QuadPrecision") + fftw_find_precision(QuadPrecision L "fftw3l_mpi-3;fftw3l_mpi;fftwl_mpi" fftwl_mpi_init MPI) + endif() + + # also look for MPI fortran header if we requested fortran and MPI + if("${FFTW_FIND_COMPONENTS}" MATCHES "Fortran" AND FFTW_Fortran_FOUND) + + set(FFTW_FORTRAN_MPI_HEADER "${FFTW_INCLUDES_MPI}/fftw3-mpi.f03") + + # reevaluate our life choices + if(EXISTS "${FFTW_FORTRAN_MPI_HEADER}") + set(FFTW_Fortran_FOUND TRUE) + else() + set(FFTW_Fortran_FOUND FALSE) + message(STATUS "Cannot find FFTW Fortran headers - ${FFTW_FORTRAN_MPI_HEADER} is missing") + endif() + endif() + + set(FFTW_LIBRARIES ${FFTW_LIBRARIES_MPI} ${FFTW_LIBRARIES}) + + mark_as_advanced (FFTW_LIBRARIES_MPI FFTW_INCLUDES_MPI) + +endif() # handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if # all listed variables are TRUE include (FindPackageHandleStandardArgs) -find_package_handle_standard_args (FFTW DEFAULT_MSG FFTW_LIBRARIES FFTW_INCLUDES) +find_package_handle_standard_args (FFTW REQUIRED_VARS ${FFTW_REQUIRED_VARIABLES}) + +mark_as_advanced(${FFTW_REQUIRED_VARIABLES}) + +# dump variables in debug mode +if(FIND_FFTW_DEBUG) + message("FFTW_COMPILE_OPTIONS: ${FFTW_COMPILE_OPTIONS}") + message("FFTW_INCLUDES: ${FFTW_INCLUDES}") + message("FFTW_LIBRARIES: ${FFTW_LIBRARIES}") + message("FFTW_FOUND: ${FFTW_FOUND}") + message("FFTW_IS_SHARED: ${FFTW_IS_SHARED}") +endif() + +# import targets +if(FFTW_FOUND) + + + # main lib (double precision) + add_library(fftw::fftwl UNKNOWN IMPORTED) + set_property(TARGET fftw::fftwl PROPERTY IMPORTED_LOCATION ${FFTW_LIBRARY_SERIAL}) + set_property(TARGET fftw::fftwl PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_SERIAL}) + set_property(TARGET fftw::fftwl PROPERTY INTERFACE_COMPILE_OPTIONS ${FFTW_COMPILE_OPTIONS}) + + set(FFTW_ALL_IMPORTED_LIBRARIES fftw::fftwl) + + if(FFTW_SinglePrecision_FOUND) + add_library(fftw::fftwf UNKNOWN IMPORTED) + set_property(TARGET fftw::fftwf PROPERTY IMPORTED_LOCATION ${FFTWF_LIBRARY_SERIAL}) + set_property(TARGET fftw::fftwf PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_SERIAL}) + set_property(TARGET fftw::fftwf PROPERTY INTERFACE_COMPILE_OPTIONS ${FFTW_COMPILE_OPTIONS}) + + list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::fftwf) + endif() + + if(FFTW_QuadPrecision_FOUND) + add_library(fftw::fftwq UNKNOWN IMPORTED) + set_property(TARGET fftw::fftwq PROPERTY IMPORTED_LOCATION ${FFTWQ_LIBRARY_SERIAL}) + set_property(TARGET fftw::fftwq PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_SERIAL}) + set_property(TARGET fftw::fftwq PROPERTY INTERFACE_COMPILE_OPTIONS ${FFTW_COMPILE_OPTIONS}) + + list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::fftwq) + endif() + + if(FFTW_MPI_FOUND) + add_library(fftw::mpi_l UNKNOWN IMPORTED) + set_property(TARGET fftw::mpi_l PROPERTY IMPORTED_LOCATION ${FFTW_LIBRARY_MPI}) + set_property(TARGET fftw::mpi_l PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_MPI}) + set_property(TARGET fftw::mpi_l PROPERTY INTERFACE_LINK_LIBRARIES fftw::fftwl) + + list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::mpi_l) + + if(FFTW_SinglePrecision_FOUND) + add_library(fftw::mpi_f UNKNOWN IMPORTED) + set_property(TARGET fftw::mpi_f PROPERTY IMPORTED_LOCATION ${FFTWF_LIBRARY_MPI}) + set_property(TARGET fftw::mpi_f PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_MPI}) + set_property(TARGET fftw::mpi_f PROPERTY INTERFACE_LINK_LIBRARIES fftw::fftwf) + + list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::mpi_f) + endif() + + if(FFTW_QuadPrecision_FOUND) + add_library(fftw::mpi_q UNKNOWN IMPORTED) + set_property(TARGET fftw::mpi_q PROPERTY IMPORTED_LOCATION ${FFTWQ_LIBRARY_MPI}) + set_property(TARGET fftw::mpi_q PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES_MPI}) + set_property(TARGET fftw::mpi_q PROPERTY INTERFACE_LINK_LIBRARIES fftw::fftwq) + + list(APPEND FFTW_ALL_IMPORTED_LIBRARIES fftw::mpi_q) + endif() + + endif() + + # add combined target + add_library(fftw::fftw INTERFACE IMPORTED) + set_property(TARGET fftw::fftw PROPERTY INTERFACE_LINK_LIBRARIES ${FFTW_ALL_IMPORTED_LIBRARIES}) + set_property(TARGET fftw::fftw PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_INCLUDES}) + +endif() -mark_as_advanced (FFTW_LIBRARIES FFTW_INCLUDES) +# don't leak required libraries +set(CMAKE_REQUIRED_LIBRARIES "") \ No newline at end of file diff --git a/host/cmake/modules/FindLIBHACKRF.cmake b/host/cmake/modules/FindLIBHACKRF.cmake index a97fec59b..fe66b2916 100644 --- a/host/cmake/modules/FindLIBHACKRF.cmake +++ b/host/cmake/modules/FindLIBHACKRF.cmake @@ -4,6 +4,10 @@ # LIBHACKRF_FOUND - system has libhackrf # LIBHACKRF_INCLUDE_DIR - the libhackrf include directory # LIBHACKRF_LIBRARIES - Link these to use libhackrf +# LIBHACKRF_COMPILE_OPTIONS - Add these compile options when using libhackrf +# +# If libhackrf is found, the following imported target is created: +# libhackrf::libhackrf # Copyright (c) 2013 Benjamin Vernoux # @@ -12,44 +16,60 @@ if (LIBHACKRF_INCLUDE_DIR AND LIBHACKRF_LIBRARIES) # in cache already - set(LIBHACKRF_FOUND TRUE) - -else (LIBHACKRF_INCLUDE_DIR AND LIBHACKRF_LIBRARIES) - IF (NOT WIN32) - # use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - find_package(PkgConfig) - pkg_check_modules(PC_LIBHACKRF QUIET libhackrf) - ENDIF(NOT WIN32) - - FIND_PATH(LIBHACKRF_INCLUDE_DIR - NAMES hackrf.h - HINTS $ENV{LIBHACKRF_DIR}/include ${PC_LIBHACKRF_INCLUDEDIR} - PATHS /usr/local/include/libhackrf /usr/include/libhackrf /usr/local/include - /usr/include ${CMAKE_SOURCE_DIR}/../libhackrf/src - /opt/local/include/libhackrf - ${LIBHACKRF_INCLUDE_DIR} - ) - - set(libhackrf_library_names hackrf) - - FIND_LIBRARY(LIBHACKRF_LIBRARIES - NAMES ${libhackrf_library_names} - HINTS $ENV{LIBHACKRF_DIR}/lib ${PC_LIBHACKRF_LIBDIR} - PATHS /usr/local/lib /usr/lib /opt/local/lib ${PC_LIBHACKRF_LIBDIR} ${PC_LIBHACKRF_LIBRARY_DIRS} ${CMAKE_SOURCE_DIR}/../libhackrf/src - ) - - if(LIBHACKRF_INCLUDE_DIR) - set(CMAKE_REQUIRED_INCLUDES ${LIBHACKRF_INCLUDE_DIR}) - endif() + set(LIBHACKRF_FIND_QUIETLY TRUE) +endif() + +IF (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + pkg_check_modules(PC_LIBHACKRF QUIET libhackrf) +ENDIF(NOT WIN32) + +FIND_PATH(LIBHACKRF_INCLUDE_DIR + NAMES hackrf.h + HINTS $ENV{LIBHACKRF_DIR}/include ${PC_LIBHACKRF_INCLUDEDIR} + PATH_SUFFIXES libhackrf +) + +set(libhackrf_library_names hackrf hackrf_static) - if(LIBHACKRF_LIBRARIES) - set(CMAKE_REQUIRED_LIBRARIES ${LIBHACKRF_LIBRARIES}) +FIND_LIBRARY(LIBHACKRF_LIBRARY + NAMES ${libhackrf_library_names} + HINTS $ENV{LIBHACKRF_DIR}/lib ${PC_LIBHACKRF_LIBDIR} + PATHS /usr/local/lib /usr/lib /opt/local/lib ${PC_LIBHACKRF_LIBRARY_DIRS} +) + +# set up shared vs static compile flags (need to check type of library) +set(LIBHACKRF_COMPILE_OPTIONS "") +if(EXISTS "${LIBHACKRF_LIBRARY}") + get_lib_type(${LIBHACKRF_LIBRARY} HACKRF_LIB_TYPE) + + if(HACKRF_LIB_TYPE STREQUAL "STATIC") + list(APPEND LIBHACKRF_COMPILE_OPTIONS -Dhackrf_STATIC) endif() +endif() + +# If we found a static libhackrf, we need to also link in libusb and pthread that were found earlier in order for it to be able to link. +set(LIBHACKRF_EXTRA_LIBS ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +set(LIBHACKRF_LIBRARIES ${LIBHACKRF_LIBRARY} ${LIBHACKRF_EXTRA_LIBS}) + +try_link_library(LIBHACKRF_WORKS + LANGUAGE C + FUNCTION hackrf_init + LIBRARIES ${LIBHACKRF_LIBRARIES}) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBHACKRF DEFAULT_MSG LIBHACKRF_LIBRARY LIBHACKRF_INCLUDE_DIR LIBHACKRF_WORKS) - include(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBHACKRF DEFAULT_MSG LIBHACKRF_LIBRARIES LIBHACKRF_INCLUDE_DIR) +MARK_AS_ADVANCED(LIBHACKRF_INCLUDE_DIR LIBHACKRF_LIBRARY) - MARK_AS_ADVANCED(LIBHACKRF_INCLUDE_DIR LIBHACKRF_LIBRARIES) +# Create imported target if hackrf was found +if(LIBHACKRF_FOUND) + add_library(libhackrf::libhackrf UNKNOWN IMPORTED) + set_property(TARGET libhackrf::libhackrf PROPERTY IMPORTED_LOCATION ${LIBHACKRF_LIBRARY}) + set_property(TARGET libhackrf::libhackrf PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LIBHACKRF_INCLUDE_DIR}) + set_property(TARGET libhackrf::libhackrf PROPERTY INTERFACE_LINK_LIBRARIES ${LIBHACKRF_EXTRA_LIBS}) + set_property(TARGET libhackrf::libhackrf PROPERTY INTERFACE_COMPILE_OPTIONS ${LIBHACKRF_COMPILE_OPTIONS}) -endif (LIBHACKRF_INCLUDE_DIR AND LIBHACKRF_LIBRARIES) \ No newline at end of file +endif() diff --git a/host/cmake/modules/FindThreads.cmake b/host/cmake/modules/FindThreads.cmake index 8028b1584..e0e0d1f76 100644 --- a/host/cmake/modules/FindThreads.cmake +++ b/host/cmake/modules/FindThreads.cmake @@ -84,11 +84,13 @@ ELSEIF(_Threads_ptwin32) # Determine the library filename IF(MSVC) - SET(_Threads_pthreads_libname - pthreadV${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2) + SET(_Threads_pthreads_libnames + pthreadV${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2 + pthreadV${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}3) ELSEIF(MINGW) - SET(_Threads_pthreads_libname - pthreadG${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2) + SET(_Threads_pthreads_libnames + pthreadG${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2 + pthreadG${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}3) ELSE() MESSAGE(FATAL_ERROR "This should never happen") ENDIF() @@ -101,7 +103,7 @@ ELSEIF(_Threads_ptwin32) SET(_Threads_lib_paths ${_Threads_root_dir}/lib) ENDIF() FIND_LIBRARY(THREADS_PTHREADS_WIN32_LIBRARY - NAMES ${_Threads_pthreads_libname} + NAMES ${_Threads_pthreads_libnames} PATHS ${_Threads_lib_paths} DOC "The Portable Threads Library for Win32" NO_SYSTEM_PATH diff --git a/host/cmake/modules/FindUSB1.cmake b/host/cmake/modules/FindUSB1.cmake index 2f3138dca..b55d67c8d 100644 --- a/host/cmake/modules/FindUSB1.cmake +++ b/host/cmake/modules/FindUSB1.cmake @@ -1,4 +1,4 @@ -# - Try to find the freetype library +# - Try to find the libusb library # Once done this defines # # LIBUSB_FOUND - system has libusb @@ -14,30 +14,42 @@ if (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) # in cache already - set(LIBUSB_FOUND TRUE) + set(USB1_FIND_QUIETLY TRUE) +endif() -else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) - IF (NOT WIN32) - # use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - find_package(PkgConfig) - pkg_check_modules(PC_LIBUSB libusb-1.0) - ENDIF(NOT WIN32) - set(LIBUSB_LIBRARY_NAME usb-1.0) - IF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") - set(LIBUSB_LIBRARY_NAME usb) - ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") +IF (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + pkg_check_modules(PC_LIBUSB libusb-1.0) +ENDIF() - FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h - PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}) +set(LIBUSB_LIBRARY_NAMES usb-1.0) +IF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + set(LIBUSB_LIBRARY_NAMES usb) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - FIND_LIBRARY(LIBUSB_LIBRARIES NAMES ${LIBUSB_LIBRARY_NAME} - PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) + # vcpkg's libusb-1.0 has a "lib" prefix, but on Windows MVSC, CMake doesn't search for + # static libraries with lib prefixes automatically. + list(APPEND LIBUSB_LIBRARY_NAMES libusb-1.0) +endif() - include(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR) - MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) +FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h + PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS} + PATH_SUFFIXES libusb-1.0) + +FIND_LIBRARY(LIBUSB_LIBRARIES NAMES ${LIBUSB_LIBRARY_NAMES} + PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) + +try_link_library(LIBUSB1_WORKS + LANGUAGE C + FUNCTION libusb_init + LIBRARIES ${LIBUSB_LIBRARIES}) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(USB1 DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR LIBUSB1_WORKS) + +MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) -endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) \ No newline at end of file diff --git a/host/cmake/modules/amber-cmake/FindCMath.cmake b/host/cmake/modules/amber-cmake/FindCMath.cmake new file mode 100644 index 000000000..9a59231f5 --- /dev/null +++ b/host/cmake/modules/amber-cmake/FindCMath.cmake @@ -0,0 +1,92 @@ +#[=======================================================================[.rst: +FindCMath +------- + +Finds the C Math library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following imported targets, if found: + +``C::Math`` + The C math library + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``CMath_FOUND`` + True if the system has the C math library. + +``CMath_LIBRARIES`` + List of C math libraries. Might be empty. + +#]=======================================================================] + +include(CMakePushCheckState) +include(CheckCSourceCompiles) + +set(CHECK_SINE_C_SOURCE "#include + +int main(int argc, char** argv) +{ + return sin(argc - 1); +}") + +set(CMath_WORKS FALSE) + +check_c_source_compiles("${CHECK_SINE_C_SOURCE}" CMath_LINKS_WITHOUT_M) + +if ("${CMath_LINKS_WITHOUT_M}") + set(CMath_LIBRARIES "") +else() + find_library(CMath_LIBRARIES NAMES m math libm) + + if(EXISTS "${CMath_LIBRARIES}") + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "") + set(CMAKE_REQUIRED_LIBRARIES "${CMath_LIBRARIES}") + check_c_source_compiles("${CHECK_SINE_C_SOURCE}" CMath_LINKS_WITH_M) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_SAVE_CMATH}) + set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE_CMATH}) + cmake_pop_check_state() + else() + set(CMath_LINKS_WITH_M FALSE) + endif() +endif () + +if (("${CMath_LINKS_WITH_M}" OR "${CMath_LINKS_WITHOUT_M}") ) + set(CMath_WORKS TRUE) +endif() + +# we want FPHSA to print a library path when libm is found as a library +if(CMath_LINKS_WITH_M) + set(CMath_REQUIRED_VARS CMath_LIBRARIES CMath_WORKS) +else() + set(CMath_REQUIRED_VARS CMath_WORKS) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CMath DEFAULT_MSG ${CMath_REQUIRED_VARS}) + +if ("${CMath_FOUND}" AND NOT TARGET C::Math) + + if(CMath_LINKS_WITH_M) + # create imported target + import_library(C::Math "${CMath_LIBRARIES}") + else() + # create empty target + add_library(C::Math INTERFACE IMPORTED GLOBAL) + endif() + +endif () + + +# Mark variables as advanced, effectively hiding from ccmake interface +mark_as_advanced( + CMath_LINKS_WITHOUT_M + CMath_LINKS_WITH_M + CMath_LIBRARIES +) \ No newline at end of file diff --git a/host/cmake/modules/amber-cmake/LibraryUtils.cmake b/host/cmake/modules/amber-cmake/LibraryUtils.cmake new file mode 100644 index 000000000..c7adeea62 --- /dev/null +++ b/host/cmake/modules/amber-cmake/LibraryUtils.cmake @@ -0,0 +1,292 @@ +# Script containing several advanced functions for handling libraries in CMake. + +# linker flag prefix -- if a link library starts with this character, it will be ignored by import_libraries() +# this is needed because things can return linker flags mixed with its libraries (which is actually the official CMake way of doing things) +if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + set(LINKER_FLAG_PREFIX "/") # stupid illogical MSVC command-line format... +else() + set(LINKER_FLAG_PREFIX "-") +endif() + + +#Unfortunately, CMake doesn't let you import a library without knowing whether it is shared or static, and there's no easy way to tell which it is. +#sets OUTPUT_VARAIBLE to "IMPORT", "SHARED", or "STATIC" depending on the library passed +function(get_lib_type LIBRARY OUTPUT_VARIABLE) + + if(NOT EXISTS ${LIBRARY}) + message(FATAL_ERROR "get_lib_type(): library ${LIBRARY} does not exist!") + endif() + + get_filename_component(LIB_NAME ${LIBRARY} NAME) + + set(CACHE_VAR_NAME GET_LIB_TYPE_CACHED_RESULT_${LIB_NAME}) + + if((DEFINED ${CACHE_VAR_NAME}) AND ("${${CACHE_VAR_NAME}}" STREQUAL "SHARED" OR "${${CACHE_VAR_NAME}}" STREQUAL "STATIC" OR "${${CACHE_VAR_NAME}}" STREQUAL "IMPORT")) + + # use cache variable + set(${OUTPUT_VARIABLE} ${${CACHE_VAR_NAME}} PARENT_SCOPE) + return() + endif() + + # first, check for import libraries + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + if(MINGW) + # on MinGW, import libraries have a different file extension, so our job is easy. + if(${LIB_NAME} MATCHES ".*${CMAKE_IMPORT_LIBRARY_SUFFIX}") + set(LIB_TYPE IMPORT) + endif() + else() # MSVC, Intel, or some other Windows compiler + + # we have to work a little harder, and use Dumpbin to check the library type, since import and static libraries have the same extensions + get_filename_component(CL_INSTALL_DIR ${CMAKE_C_COMPILER} DIRECTORY) + find_program(DUMPBIN dumpbin HINTS ${CL_INSTALL_DIR}) + + if(NOT DUMPBIN) + message(FATAL_ERROR "The Microsoft Dumpbin tool was not found. It is needed to analyze libraries, so please set the DUMPBIN variable to point to it.") + endif() + + # NOTE: this can take around 2-5 seconds for large libraries -- hence why we cache the result of this function + execute_process(COMMAND ${DUMPBIN} -headers ${LIBRARY} OUTPUT_VARIABLE DUMPBIN_OUTPUT ERROR_VARIABLE DUMPBIN_ERROUT RESULT_VARIABLE DUMPBIN_RESULT) + + # sanity check + if(NOT ${DUMPBIN_RESULT} EQUAL 0) + message(FATAL_ERROR "Could not analyze the type of library ${LIBRARY}: dumpbin failed to execute with output ${DUMPBIN_OUTPUT} and error message ${DUMPBIN_ERROUT}") + endif() + + # check for dynamic symbol entries + # https://stackoverflow.com/questions/488809/tools-for-inspecting-lib-files + if("${DUMPBIN_OUTPUT}" MATCHES "Symbol name :") + # found one! It's an import library! + set(LIB_TYPE IMPORT) + else() + # by process of elimination, it's a static library + set(LIB_TYPE STATIC) + endif() + endif() + endif() + + # now we can figure the rest out by suffix matching + if((NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") OR (CMAKE_SYSTEM_NAME STREQUAL "Windows" AND MINGW AND "${LIB_TYPE}" STREQUAL "")) + if(${LIB_NAME} MATCHES ".*${CMAKE_SHARED_LIBRARY_SUFFIX}") + set(LIB_TYPE SHARED) + elseif(${LIB_NAME} MATCHES ".*${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(LIB_TYPE STATIC) + else() + message(FATAL_ERROR "Could not determine whether \"${LIBRARY}\" is a static or shared library, it does not have a known suffix.") + endif() + endif() + + set(${OUTPUT_VARIABLE} ${LIB_TYPE} PARENT_SCOPE) + set(${CACHE_VAR_NAME} ${LIB_TYPE} CACHE INTERNAL "Result of get_lib_type() for ${LIB_NAME}" FORCE) + +endfunction(get_lib_type) + +# Takes a list of CMake libraries that you might pass to a target, and returns a list of resolved library paths that correspond to it. +# Some libraries are known by full path, others are known by link-name only (as in, the name you'd pass to "ld -l"). They'll be returned in order in LIB_PATHS. +# Accepts 5 types of thing: full paths to libraries, CMake library targets built by this project, CMake imported targets, CMake interface targets (returns their INTERFACE_LINK_LIBRARIES), and regular linker library names. + +# For example, on my system, +# resolve_cmake_library_list("-Wl,--no-as-needed;mkl::core;mkl::threading;mkl::fortran_interface;/usr/lib/x86_64-linux-gnu/libdl.so;Threads::Threads;arpack;/usr/lib/x86_64-linux-gnu/libm.so") +# returns +# "-Wl,--no-as-needed;/home/jamie/anaconda3/lib/libmkl_core.so;/home/jamie/anaconda3/lib/libmkl_sequential.so;/home/jamie/anaconda3/lib/libmkl_gf_lp64.so;/usr/lib/x86_64-linux-gnu/libdl.so;-lpthread;arpack;/usr/lib/x86_64-linux-gnu/libm.so" + +# usage: resolve_cmake_library_list( ) +function(resolve_cmake_library_list LIB_PATH_OUTPUT) + # we don't want to add generator expressions to the library tracker... + string(GENEX_STRIP "${ARGN}" LIBS_TO_RESOLVE) + + set(LIB_PATHS "") + + foreach(LIBRARY ${LIBS_TO_RESOLVE}) + if("${LIBRARY}" MATCHES "^${LINKER_FLAG_PREFIX}") + # linker flag + list(APPEND LIB_PATHS "${LIBRARY}") + + elseif(EXISTS "${LIBRARY}") + # full path to library + list(APPEND LIB_PATHS "${LIBRARY}") + + elseif(TARGET "${LIBRARY}") + + get_property(TARGET_LIB_TYPE TARGET ${LIBRARY} PROPERTY TYPE) + + # it's an error to check if an interface library has an imported location + if("${TARGET_LIB_TYPE}" STREQUAL "INTERFACE_LIBRARY") + + # interface library -- but it will have dependencies that we need to get. + get_property(INTERFACE_LIB_DEPENDENCIES TARGET ${LIBRARY} PROPERTY INTERFACE_LINK_LIBRARIES) + + if(NOT "${INTERFACE_LIB_DEPENDENCIES}" STREQUAL "") + + # avoid crashing CMake if somebody accidentally made an interface library depend on itself + list(REMOVE_ITEM INTERFACE_LIB_DEPENDENCIES "${LIBRARY}") + + # now parse those dependencies! + resolve_cmake_library_list(INTERFACE_DEPS_LIB_PATHS ${INTERFACE_LIB_DEPENDENCIES}) + + list(APPEND LIB_PATHS ${INTERFACE_DEPS_LIB_PATHS}) + endif() + else() + # must be either imported or an actual target + get_property(LIBRARY_HAS_IMPORTED_LOCATION TARGET ${LIBRARY} PROPERTY IMPORTED_LOCATION SET) + if(LIBRARY_HAS_IMPORTED_LOCATION) + # CMake imported target + get_property(LIBRARY_IMPORTED_LOCATION TARGET ${LIBRARY} PROPERTY IMPORTED_LOCATION) + list(APPEND LIB_PATHS "${LIBRARY_IMPORTED_LOCATION}") + + else() + # else it's a CMake target that is built by this project + + # detect if the library has been renamed + get_property(LIB_NAME TARGET ${LIBRARY} PROPERTY OUTPUT_NAME) + + if("${LIB_NAME}" STREQUAL "") + # use target name if output name was not set + set(LIB_NAME ${LIBRARY}) + endif() + + list(APPEND LIB_PATHS ${LIB_NAME}) + endif() + endif() + else() + + # otherwise it's a library name to find on the linker search path (using CMake in "naive mode") + list(APPEND LIB_PATHS ${LIBRARY}) + endif() + + endforeach() + + # debugging code + if(FALSE) + message("resolve_cmake_library_list(${LIBS_TO_RESOLVE}):") + message(" -> ${LIB_PATHS}") + endif() + + set(${LIB_PATH_OUTPUT} ${LIB_PATHS} PARENT_SCOPE) +endfunction(resolve_cmake_library_list) + +# gets the "linker name" (the name you'd pass to "ld -l") for a library file. + +function(get_linker_name LIBRARY_PATH OUTPUT_VARIABLE) + + # get full library name + get_filename_component(LIBNAME "${LIBRARY_PATH}" NAME) + + #remove prefix + string(REGEX REPLACE "^lib" "" LIBNAME "${LIBNAME}") + + #remove numbers after the file extension + string(REGEX REPLACE "(\\.[0-9])+$" "" LIBNAME "${LIBNAME}") + + #remove the file extension + get_lib_type(${LIBRARY_PATH} LIB_TYPE) + + if("${LIB_TYPE}" STREQUAL "IMPORT") + string(REGEX REPLACE "${CMAKE_IMPORT_LIBRARY_SUFFIX}$" "" LIBNAME ${LIBNAME}) + elseif("${LIB_TYPE}" STREQUAL "STATIC") + string(REGEX REPLACE "${CMAKE_STATIC_LIBRARY_SUFFIX}\$" "" LIBNAME ${LIBNAME}) + else() + string(REGEX REPLACE "${CMAKE_SHARED_LIBRARY_SUFFIX}\$" "" LIBNAME ${LIBNAME}) + endif() + + set(${OUTPUT_VARIABLE} ${LIBNAME} PARENT_SCOPE) +endfunction(get_linker_name) + +# Converts the result of resolve_cmake_library_list() into a "link line" ready to be passed to gcc or ld, and a +# list of directories to add to the search path. +macro(resolved_lib_list_to_link_line LINK_LINE_VAR DIRS_VAR) # ARGN: LIB_PATH_LIST + + set(${LINK_LINE_VAR} "") + set(${DIRS_VAR} "") + + foreach(LIBRARY ${ARGN}) + if("${LIBRARY}" MATCHES "^${LINKER_FLAG_PREFIX}") + + # linker flag -- put in library list to preserve ordering + list(APPEND ${LINK_LINE_VAR} "${LIBRARY}") + elseif("${LIBRARY}" MATCHES "(.+)\\.framework") + + # OS X framework -- translate to "-framework" linker flag + get_filename_component(FRAMEWORK_BASENAME "${LIBRARY}" NAME_WE) + string(TOLOWER "${FRAMEWORK_BASENAME}" FRAMEWORK_BASENAME_LCASE) + list(APPEND ${LINK_LINE_VAR} "-framework" "${FRAMEWORK_BASENAME_LCASE}") + + elseif(EXISTS "${LIBRARY}") + + if(NOT IS_DIRECTORY "${LIBRARY}") + # full path to library + get_filename_component(LIB_DIR ${LIBRARY} DIRECTORY) + list(APPEND ${DIRS_VAR} ${LIB_DIR}) + + get_linker_name("${LIBRARY}" LIB_LINK_NAME) + list(APPEND ${LINK_LINE_VAR} "-l${LIB_LINK_NAME}") + + endif() + + else() + + # target built by this project + list(APPEND ${LINK_LINE_VAR} "-l${LIBRARY}") + + endif() + endforeach() + + list(REMOVE_DUPLICATES ${DIRS_VAR}) + +endmacro(resolved_lib_list_to_link_line) + +# import functions +# -------------------------------------------------------------------- + +# Shorthand for setting up a CMake imported target for a library file, with a path and include directories. +# After calling this function, using NAME in a library list will tell CMake to link to the provided file, and add the provided include directories. +# Automatically adds the library to the library tracker. + +#usage: import_library( [include dir 1] [include dir 2]...) +function(import_library NAME PATH) #3rd arg: INCLUDE_DIRS + + #Try to figure out whether it is shared or static. + get_lib_type(${PATH} LIB_TYPE) + + if("${LIB_TYPE}" STREQUAL "SHARED") + add_library(${NAME} SHARED IMPORTED GLOBAL) + else() + add_library(${NAME} STATIC IMPORTED GLOBAL) + endif() + + set_property(TARGET ${NAME} PROPERTY IMPORTED_LOCATION ${PATH}) + set_property(TARGET ${NAME} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ARGN}) + +endfunction(import_library) + +# Shorthand for adding one library target which corresponds to multiple linkable things. +# "linkable things" can be any of 6 different types: +# 1. CMake imported targets (as created by import_library() or by another module) +# 2. File paths to libraries +# 3. CMake non-imported targets +# 4. Linker flags +# 5. Names of libraries to find on the linker path +# 6. Generator expressions + +# Things of the first 2 types are added to the library tracker. + +#usage: import_libraries( LIBRARIES INCLUDES []) +function(import_libraries NAME) + + cmake_parse_arguments(IMP_LIBS "" "" "LIBRARIES;INCLUDES" ${ARGN}) + + if("${IMP_LIBS_LIBRARIES}" STREQUAL "") + message(FATAL_ERROR "Incorrect usage. At least one LIBRARY should be provided.") + endif() + + if(NOT "${IMP_LIBS_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Incorrect usage. Extra arguments provided.") + endif() + + # we actually don't use imported libraries at all; we just create an interface target and set its dependencies + add_library(${NAME} INTERFACE) + + set_property(TARGET ${NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${IMP_LIBS_LIBRARIES}) + set_property(TARGET ${NAME} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${IMP_LIBS_INCLUDES}) + +endfunction(import_libraries) \ No newline at end of file diff --git a/host/cmake/modules/amber-cmake/TryLinkLibrary.cmake b/host/cmake/modules/amber-cmake/TryLinkLibrary.cmake new file mode 100644 index 000000000..21f7d312a --- /dev/null +++ b/host/cmake/modules/amber-cmake/TryLinkLibrary.cmake @@ -0,0 +1,219 @@ +#[=======================================================================[.rst: +TryLinkLibrary +------------------ + +Check if a library works and is linkable using the current compiler. This works by compiling and linking an executable file that calls one of the library's functions. + +TryLinkLibrary was designed as an upgraded replacement for the modules CheckLibraryExists and CheckC(XX)SourceCompiles. It can replace any existing usage of these modules with a more convenient and flexible syntax. It can also handle other situations, such as Fortran code and Windows DLLs. Last but not least, it can work with imported and interface targets in its LIBRARIES, so it's compatible with newer find modules that only provide imported targets. + +By default, source code for a void no-argument function prototype is generated according to the function name and then called in the test code. This will work for most cases, but breaks in certain scenarios: + +- DLL imports/exports on Windows. This requires the function to be declared with a specific prefix, like "extern" or "extern __declspec(dllimport)". Use the FUNC_PREFIX option to set this. +- C++ mangling. C++ functions have different symbol names based on their arguments and return type. For C++, use the FUNC_DECLARATION and FUNC_CALL options to specify custom blocks of code for this. +- Fortran modules. Requires a seperate use statement and then a function call. Use FUNC_CALL to provide code for this. + +.. command:: try_link_library + + .. code-block:: cmake + + try_link_library( + LANGUAGE + FUNCTION + [LIBRARIES ] + [INCLUDES ] + [FUNC_PREFIX ] + [FUNC_DECLARATION ] + [FUNC_CALL ]) + + :: + + - Name of cache variable to store result in. Gets set to TRUE or FALSE. + LANGUAGE - Language to perform the check in. Important so that mangling is done correctly. + FUNCTION - Name of function in the library to attempt to call. If both FUNC_DECLARATION and FUNC_CALL are provided, then this will only be used for status messages. + LIBRARIES - Library paths and imported targets to link when doing this check. + INCLUDES - Include paths for headers/modules that are used in the check. + FUNC_PREFIX - Optional code to put before the start of the function declaration in C and CXX. + FUNC_DECLARATION - Optional code to use in place of the default function declaration in C and CXX. Must prepare the named function to be called later in the code. Can be multiline. Can also include the library's header if that is easier to work with. + FUNC_CALL - Optional code to use to call the function. Can be multiline. NOTE: CMake argument passing weirdness prevents a trailing semicolon from being passed in FUNC_CALL. For C and C++, a trailing semicolon is added to the code passed. + +Under some conditions, if it appears that nonexistant libraries were passed to the LIBRARIES argument or nonexistant directories were passed to INCLUDES, the check will immediately +report false since preceding code has clearly failed to find the needed libraries. This will happen if: +* A library is not a target and ends in -NOTFOUND +* A library is an imported target name (containing "::"), but does not currently exist +* An include ends in -NOTFOUND + +The following variables may be set before calling this macro to modify +the way the check is run: + +:: + + CMAKE_REQUIRED_FLAGS = string of compile command line flags + CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) + CMAKE_REQUIRED_LINK_OPTIONS = list of options to pass to link command + CMAKE_REQUIRED_LIBRARIES = list of additonal libraries to link + CMAKE_REQUIRED_QUIET = execute quietly without messages + CMAKE_POSITION_INDEPENDENT_CODE = whether to compile a position independent executable (and therefore require the checked libraries to be position independent) +#]=======================================================================] + +function(try_link_library RESULT_VAR) + + if(DEFINED "${RESULT_VAR}") + # already in cache + return() + endif() + + # Parse arguments + # ---------------------------------------------------------- + # NOTE: FUNC_DECLARATION and FUNC_CALL must be listed as multi-value arguments in order to allow code containing semicolons + cmake_parse_arguments(TLL "" "LANGUAGE;FUNCTION;FUNC_PREFIX" "LIBRARIES;INCLUDES;FUNC_DECLARATION;FUNC_CALL" ${ARGN}) + + if("${TLL_LANGUAGE}" STREQUAL "" OR "${TLL_FUNCTION}" STREQUAL "") + message(FATAL_ERROR "Usage error: required arguments missing.") + endif() + + if(NOT "${TLL_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Usage error: extra or unparsed arguments provided.") + endif() + + if(NOT ("${TLL_LANGUAGE}" STREQUAL "C" OR "${TLL_LANGUAGE}" STREQUAL "CXX" OR "${TLL_LANGUAGE}" STREQUAL "Fortran")) + message(FATAL_ERROR "Usage error: unsupported LANGUAGE.") + endif() + + if(NOT "${CMAKE_${TLL_LANGUAGE}_COMPILER_LOADED}") + message(FATAL_ERROR "Error: no compiler for ${TLL_LANGUAGE} has been loaded.") + endif() + + # Write source file + # ---------------------------------------------------------- + + if("${TLL_LANGUAGE}" STREQUAL "C") + set(SOURCE_EXTENSION ".c") + elseif("${TLL_LANGUAGE}" STREQUAL "CXX") + set(SOURCE_EXTENSION ".cpp") + elseif("${TLL_LANGUAGE}" STREQUAL "Fortran") + set(SOURCE_EXTENSION ".F90") + endif() + + set(SOURCE_FILE_PATH "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/TryLinkLibrary${SOURCE_EXTENSION}") + + if("${TLL_LANGUAGE}" STREQUAL "Fortran") + + if("${TLL_FUNC_CALL}" STREQUAL "") + set(TLL_FUNC_CALL "call ${TLL_FUNCTION}()") + endif() + + file(WRITE ${SOURCE_FILE_PATH} +"program testf + ${TLL_FUNC_CALL} +end program testf +") + + else() # C or CXX + + if("${TLL_FUNC_DECLARATION}" STREQUAL "") + set(TLL_FUNC_DECLARATION "void ${TLL_FUNCTION}();") + endif() + + if("${TLL_FUNC_CALL}" STREQUAL "") + set(TLL_FUNC_CALL "${TLL_FUNCTION}()") + endif() + + file(WRITE ${SOURCE_FILE_PATH} " +${TLL_FUNC_PREFIX} ${TLL_FUNC_DECLARATION} + +int main(int argc, char** args) +{ + ${TLL_FUNC_CALL}; + return 0; +}") + + endif() + + # Gather libraries + # ---------------------------------------------------------- + set(ALL_LIBRARIES ${TLL_LIBRARIES} ${CMAKE_REQUIRED_LIBRARIES}) + + # convert library targets to paths + resolve_cmake_library_list(ALL_LIBRARY_PATHS ${ALL_LIBRARIES}) + + # check for missing libraries + set(MISSING_LIBRARIES FALSE) + foreach(LIBRARY ${ALL_LIBRARY_PATHS}) + if("${LIBRARY}" MATCHES "-NOTFOUND$") + set(MISSING_LIBRARIES TRUE) + elseif(NOT EXISTS "${LIBRARY}") + # resolved library is not a full path, so it must be a target or a library to be linked with -l + if("${LIBRARY}" MATCHES "::") + # library has an imported target name. Passing an unresolved target with this name to try_compile would cause a + # cmake error, so we have to bail out here. + set(MISSING_LIBRARIES TRUE) + endif() + endif() + endforeach() + + # Also check for NOTFOUND includes + foreach(INCLUDE ${TLL_INCLUDES}) + if("${INCLUDE}" MATCHES "-NOTFOUND$") + set(MISSING_LIBRARIES TRUE) + endif() + endforeach() + + if(MISSING_LIBRARIES) + set(${RESULT_VAR} FALSE PARENT_SCOPE) + return() + endif() + + # generate message text + set(LIBRARY_MESSAGE_TEXT "") + foreach(LIBRARY ${ALL_LIBRARY_PATHS}) + get_filename_component(LIBRARY_FILENAME ${LIBRARY} NAME) + string(APPEND LIBRARY_MESSAGE_TEXT " ${LIBRARY_FILENAME}") + endforeach() + + # Compile the code + # ---------------------------------------------------------- + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${TLL_FUNCTION} in${LIBRARY_MESSAGE_TEXT}") + endif() + try_compile(${RESULT_VAR} + ${CMAKE_BINARY_DIR} + SOURCES ${SOURCE_FILE_PATH} + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + LINK_LIBRARIES ${ALL_LIBRARY_PATHS} + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES=${TLL_INCLUDES}" + OUTPUT_VARIABLE TRY_COMPILE_OUTPUT) + + if(${RESULT_VAR}) + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${TLL_FUNCTION} in${LIBRARY_MESSAGE_TEXT} - found") + endif() + + # update docstring and type + set(${RESULT_VAR} TRUE CACHE INTERNAL "Have function ${TLL_FUNCTION} in${LIBRARY_MESSAGE_TEXT}") + + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the function ${TLL_FUNCTION} exists in${LIBRARY_MESSAGE_TEXT} " + "passed with the following output:\n" + "${TRY_COMPILE_OUTPUT}\n\n") + + else() + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Looking for ${TLL_FUNCTION} in${LIBRARY_MESSAGE_TEXT} - not found") + message(STATUS "Detailed information about why this check failed can be found in ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log") + endif() + + # update docstring and type + set(${RESULT_VAR} FALSE CACHE INTERNAL "Have function ${TLL_FUNCTION} in library ${TLL_NAME}") + + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the function ${TLL_FUNCTION} exists in the library ${TLL_NAME} " + "failed with the following output:\n" + "${TRY_COMPILE_OUTPUT}\n\n") + + endif() + +endfunction(try_link_library) \ No newline at end of file diff --git a/host/cmake/set_release.cmake b/host/cmake/set_release.cmake index 6414e4854..91a78bab1 100644 --- a/host/cmake/set_release.cmake +++ b/host/cmake/set_release.cmake @@ -1,7 +1,7 @@ if(NOT DEFINED RELEASE) execute_process( COMMAND git log -n 1 --format=%h - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE GIT_EXIT_VALUE ERROR_QUIET OUTPUT_VARIABLE GIT_VERSION @@ -12,6 +12,7 @@ if(NOT DEFINED RELEASE) else (GIT_EXIT_VALUE) execute_process( COMMAND git status -s --untracked-files=no + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE DIRTY ) if ( NOT "${DIRTY}" STREQUAL "" ) diff --git a/host/hackrf-tools/CMakeLists.txt b/host/hackrf-tools/CMakeLists.txt index 5ba528326..23c118aaf 100644 --- a/host/hackrf-tools/CMakeLists.txt +++ b/host/hackrf-tools/CMakeLists.txt @@ -19,43 +19,48 @@ # Boston, MA 02110-1301, USA. # +cmake_minimum_required(VERSION 3.8) +# standard policies for CMake 3.8 +cmake_policy(VERSION 3.8) + # Based heavily upon the libftdi cmake setup. +project(hackrf-tools LANGUAGES C) + +# Run common init code +# ----------------------------------------------------- +if(NOT HACKRF_HOST_INCLUDED) + include(../cmake/hackrf-host.cmake) +endif() -cmake_minimum_required(VERSION 2.8) -project(hackrf-tools C) +# configure release definition set(PACKAGE hackrf-tools) -include(${PROJECT_SOURCE_DIR}/../cmake/set_release.cmake) +include(set_release) add_definitions(-DTOOL_RELEASE="${RELEASE}") -set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake/modules) -if(MSVC) -include_directories(getopt) -add_definitions(/D _CRT_SECURE_NO_WARNINGS) -else() -add_definitions(-Wall) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90") -endif() -if(NOT libhackrf_SOURCE_DIR) -find_package(LIBHACKRF REQUIRED) -include_directories(${LIBHACKRF_INCLUDE_DIR}) -else() -include_directories(${libhackrf_SOURCE_DIR}/src) +if(MSVC) + include_directories(getopt) endif() -add_subdirectory(src) +# Find tools dependencies +# ----------------------------------------------------- -######################################################################## -# Create uninstall target -######################################################################## +# fftw3 +find_package(FFTW COMPONENTS SinglePrecision REQUIRED) -if(NOT HackRF_SOURCE_DIR) -configure_file( - ${PROJECT_SOURCE_DIR}/../cmake/cmake_uninstall.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake -@ONLY) +# libm +find_package(CMath REQUIRED) -add_custom_target(uninstall - ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake -) +# if we are not building libhackrf, we need to find a preexisting one in the system. +if(TARGET hackrf) + # building libhackrf at the same time, use it. + set(HACKRF_LIBRARY_TARGET hackrf) +else() + # standalone tools build + find_package(LIBHACKRF REQUIRED) + set(HACKRF_LIBRARY_TARGET libhackrf::libhackrf) endif() + +# Build the code +# ----------------------------------------------------- +add_subdirectory(src) diff --git a/host/hackrf-tools/src/CMakeLists.txt b/host/hackrf-tools/src/CMakeLists.txt index 7115151c4..4629a9100 100644 --- a/host/hackrf-tools/src/CMakeLists.txt +++ b/host/hackrf-tools/src/CMakeLists.txt @@ -21,12 +21,7 @@ # Based heavily upon the libftdi cmake setup. -set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX") -find_package(FFTW REQUIRED) -include_directories(${FFTW_INCLUDES}) -get_filename_component(FFTW_LIBRARY_DIRS ${FFTW_LIBRARIES} DIRECTORY) -link_directories(${FFTW_LIBRARY_DIRS}) SET(TOOLS hackrf_transfer @@ -39,23 +34,14 @@ SET(TOOLS hackrf_operacake ) +set(TOOLS_LINK_LIBS C::Math fftw::fftw ${HACKRF_LIBRARY_TARGET}) + if(MSVC) + # use getopt support library add_library(libgetopt_static STATIC ../getopt/getopt.c ) - LIST(APPEND TOOLS_LINK_LIBS ${FFTW_LIBRARIES}) -else() - LIST(APPEND TOOLS_LINK_LIBS m fftw3f) -endif() -if(NOT libhackrf_SOURCE_DIR) - include_directories(${LIBHACKRF_INCLUDE_DIR}) - LIST(APPEND TOOLS_LINK_LIBS ${LIBHACKRF_LIBRARIES}) -else() - LIST(APPEND TOOLS_LINK_LIBS hackrf) -endif() - -if(MSVC) LIST(APPEND TOOLS_LINK_LIBS libgetopt_static) endif() diff --git a/host/hackrf-tools/src/hackrf_sweep.c b/host/hackrf-tools/src/hackrf_sweep.c index a38675a13..0e40d3ce7 100644 --- a/host/hackrf-tools/src/hackrf_sweep.c +++ b/host/hackrf-tools/src/hackrf_sweep.c @@ -45,8 +45,8 @@ typedef int bool; #endif #ifdef _WIN32 - #define _USE_MATH_DEFINES #include + #include #ifdef _MSC_VER #ifdef _WIN64 diff --git a/host/hackrf-tools/src/hackrf_transfer.c b/host/hackrf-tools/src/hackrf_transfer.c index 380bb0653..de14950b2 100644 --- a/host/hackrf-tools/src/hackrf_transfer.c +++ b/host/hackrf-tools/src/hackrf_transfer.c @@ -46,6 +46,7 @@ typedef int bool; #ifdef _WIN32 #include + #include #ifdef _MSC_VER diff --git a/host/libhackrf/CMakeLists.txt b/host/libhackrf/CMakeLists.txt index 322970e77..ae2396b98 100644 --- a/host/libhackrf/CMakeLists.txt +++ b/host/libhackrf/CMakeLists.txt @@ -19,37 +19,27 @@ # Boston, MA 02110-1301, USA. # -# Based heavily upon the libftdi cmake setup. +cmake_minimum_required(VERSION 3.8) +# standard policies for CMake 3.8 +cmake_policy(VERSION 3.8) -cmake_minimum_required(VERSION 2.8) -project(libhackrf C) -set(MAJOR_VERSION 0) -set(MINOR_VERSION 8) -set(PACKAGE libhackrf) -set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION}) -set(VERSION ${VERSION_STRING}) -add_definitions(-DLIBRARY_VERSION="${VERSION_STRING}") -include(${PROJECT_SOURCE_DIR}/../cmake/set_release.cmake) -add_definitions(-DLIBRARY_RELEASE="${RELEASE}") -set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake/modules) +# Based heavily upon the libftdi cmake setup. +project(libhackrf LANGUAGES C VERSION 0.6.0) -if(MSVC) - set(THREADS_USE_PTHREADS_WIN32 true) -else() - add_definitions(-Wall) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90") - - INCLUDE(TestBigEndian) - TEST_BIG_ENDIAN(BIGENDIAN) - if(${BIGENDIAN}) - add_definitions(-DHACKRF_BIG_ENDIAN) - endif(${BIGENDIAN}) +# Run common init code +# ----------------------------------------------------- +if(NOT HACKRF_HOST_INCLUDED) + include(../cmake/hackrf-host.cmake) endif() -find_package(USB1 REQUIRED) -find_package(Threads REQUIRED) -include_directories(${LIBUSB_INCLUDE_DIR} ${THREADS_PTHREADS_INCLUDE_DIR}) +# configure definitions for library version and release +set(PACKAGE libhackrf) +add_definitions(-DLIBRARY_VERSION="${libhackrf_VERSION}") + +include(set_release) +add_definitions(-DLIBRARY_RELEASE="${RELEASE}") +# build library add_subdirectory(src) ######################################################################## @@ -90,7 +80,7 @@ INSTALL( ) ######################################################################## -# Create Pkg Config File +# Create udev rules for hackrf devices ######################################################################## if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") @@ -134,7 +124,7 @@ if(SYSTEM_IS_LINUX) ${CMAKE_CURRENT_BINARY_DIR}/53-hackrf.rules @ONLY ) - message(STATUS "HackRF udev rules will be installed to '${UDEV_RULES_PATH}' upon running 'make install'") + message(STATUS "HackRF udev rules will be installed to '${UDEV_RULES_PATH}' upon running 'make install'. To suppress this, pass -DINSTALL_UDEV_RULES=FALSE to cmake.") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/53-hackrf.rules DESTINATION ${UDEV_RULES_PATH} COMPONENT "udev_rules") @@ -151,18 +141,4 @@ else(SYSTEM_IS_LINUX) if(INSTALL_UDEV_RULES) message(STATUS "udev rules not supported on this platform. Hide this message via -DINSTALL_UDEV_RULES=Off") endif(INSTALL_UDEV_RULES) -endif(SYSTEM_IS_LINUX) - -######################################################################## -# Create uninstall target -######################################################################## -if(NOT HackRF_SOURCE_DIR) -configure_file( - ${PROJECT_SOURCE_DIR}/../cmake/cmake_uninstall.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake -@ONLY) - -add_custom_target(uninstall - ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake -) -endif() +endif(SYSTEM_IS_LINUX) \ No newline at end of file diff --git a/host/libhackrf/src/CMakeLists.txt b/host/libhackrf/src/CMakeLists.txt index 9d54a8cde..27a17c5e9 100644 --- a/host/libhackrf/src/CMakeLists.txt +++ b/host/libhackrf/src/CMakeLists.txt @@ -23,59 +23,51 @@ # Based heavily upon the libftdi cmake setup. # Targets -set(c_sources ${CMAKE_CURRENT_SOURCE_DIR}/hackrf.c CACHE INTERNAL "List of C sources") -set(c_headers ${CMAKE_CURRENT_SOURCE_DIR}/hackrf.h CACHE INTERNAL "List of C headers") +set(LIBHACKRF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/hackrf.c) +set(LIBHACKRF_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/hackrf.h) # Dynamic library -add_library(hackrf SHARED ${c_sources}) -set_target_properties(hackrf PROPERTIES VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.0 SOVERSION 0) +add_library(hackrf SHARED ${LIBHACKRF_SOURCES}) +set_target_properties(hackrf PROPERTIES VERSION ${libhackrf_VERSION} SOVERSION 0) # Static library -add_library(hackrf-static STATIC ${c_sources}) -if(MSVC) +add_library(hackrf-static STATIC ${LIBHACKRF_SOURCES}) +if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + # avoid .lib files with identical names set_target_properties(hackrf-static PROPERTIES OUTPUT_NAME "hackrf_static") else() set_target_properties(hackrf-static PROPERTIES OUTPUT_NAME "hackrf") endif() +# prevent cleaning one target from cleaning the other set_target_properties(hackrf PROPERTIES CLEAN_DIRECT_OUTPUT 1) set_target_properties(hackrf-static PROPERTIES CLEAN_DIRECT_OUTPUT 1) # Dependencies -target_link_libraries(hackrf ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) - -# For cygwin just force UNIX OFF and WIN32 ON -if( ${CYGWIN} ) - SET(UNIX OFF) - SET(WIN32 ON) -endif( ${CYGWIN} ) +target_link_libraries(hackrf libusb pthread) +target_link_libraries(hackrf-static libusb pthread) + +# add DLL flag to dynamic version +target_compile_definitions(hackrf-static PUBLIC hackrf_STATIC) + +# add interface include directories +target_include_directories(hackrf PUBLIC .) +target_include_directories(hackrf-static PUBLIC .) + +# install DLL to bin and link library to lib +install(TARGETS hackrf + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + COMPONENT sharedlibs + ) +install(TARGETS hackrf-static + DESTINATION lib + COMPONENT staticlibs + ) +install(FILES ${LIBHACKRF_HEADERS} + DESTINATION include/${PROJECT_NAME} + COMPONENT headers + ) -if( ${UNIX} ) - install(TARGETS hackrf - LIBRARY DESTINATION lib${LIB_SUFFIX} - COMPONENT sharedlibs - ) - install(TARGETS hackrf-static - ARCHIVE DESTINATION lib${LIB_SUFFIX} - COMPONENT staticlibs - ) - install(FILES ${c_headers} - DESTINATION include/${PROJECT_NAME} - COMPONENT headers - ) -endif( ${UNIX} ) -if( ${WIN32} ) - install(TARGETS hackrf - DESTINATION bin - COMPONENT sharedlibs - ) - install(TARGETS hackrf-static - DESTINATION bin - COMPONENT staticlibs - ) - install(FILES ${c_headers} - DESTINATION include/${PROJECT_NAME} - COMPONENT headers - ) -endif( ${WIN32} ) diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 60e0303c6..214db2a33 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -28,13 +28,17 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #include #ifdef _WIN32 - #define ADD_EXPORTS - /* You should define ADD_EXPORTS *only* when building the DLL. */ - #ifdef ADD_EXPORTS - #define ADDAPI __declspec(dllexport) + /* users of the library should define hackrf_STATIC when linking to it as a static library */ + #ifdef hackrf_STATIC + #define ADDAPI #else - #define ADDAPI __declspec(dllimport) + /* hackrf_EXPORTS is only defined by CMake when building. */ + #ifdef hackrf_EXPORTS + #define ADDAPI __declspec(dllexport) + #else + #define ADDAPI __declspec(dllimport) + #endif #endif /* Define calling convention in one place, for convenience. */