# CMake wrapper for libusb (which doesn't have native CMake support)
# Builds libusb as a static library target: usb-1.0-static

cmake_minimum_required(VERSION 3.22)

set(LIBUSB_SRC_DIR "${libusb_SOURCE_DIR}/libusb")

# Core source files (all platforms)
set(LIBUSB_SOURCES
    ${LIBUSB_SRC_DIR}/core.c
    ${LIBUSB_SRC_DIR}/descriptor.c
    ${LIBUSB_SRC_DIR}/hotplug.c
    ${LIBUSB_SRC_DIR}/io.c
    ${LIBUSB_SRC_DIR}/strerror.c
    ${LIBUSB_SRC_DIR}/sync.c
)

# Platform-specific backend sources and link libraries
set(LIBUSB_PLATFORM_LIBS "")

if(APPLE)
    list(APPEND LIBUSB_SOURCES
        ${LIBUSB_SRC_DIR}/os/darwin_usb.c
        ${LIBUSB_SRC_DIR}/os/events_posix.c
        ${LIBUSB_SRC_DIR}/os/threads_posix.c
    )
    find_library(IOKIT_FRAMEWORK IOKit)
    find_library(SECURITY_FRAMEWORK Security)
    find_library(COREFOUNDATION_FRAMEWORK CoreFoundation)
    find_library(OBJC_LIB objc)
    set(LIBUSB_PLATFORM_LIBS ${IOKIT_FRAMEWORK} ${SECURITY_FRAMEWORK} ${COREFOUNDATION_FRAMEWORK} ${OBJC_LIB})
elseif(UNIX)
    list(APPEND LIBUSB_SOURCES
        ${LIBUSB_SRC_DIR}/os/linux_usbfs.c
        ${LIBUSB_SRC_DIR}/os/linux_netlink.c
        ${LIBUSB_SRC_DIR}/os/events_posix.c
        ${LIBUSB_SRC_DIR}/os/threads_posix.c
    )
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(UDEV REQUIRED libudev)
    set(LIBUSB_PLATFORM_LIBS ${UDEV_LIBRARIES} pthread)
elseif(WIN32)
    list(APPEND LIBUSB_SOURCES
        ${LIBUSB_SRC_DIR}/os/windows_common.c
        ${LIBUSB_SRC_DIR}/os/windows_usbdk.c
        ${LIBUSB_SRC_DIR}/os/windows_winusb.c
        ${LIBUSB_SRC_DIR}/os/events_windows.c
        ${LIBUSB_SRC_DIR}/os/threads_windows.c
    )
    set(LIBUSB_PLATFORM_LIBS winusb setupapi)
endif()

# Generate config.h — libusb's internal headers require it
set(_LIBUSB_CONFIG_H "${CMAKE_CURRENT_BINARY_DIR}/config.h")
file(WRITE "${_LIBUSB_CONFIG_H}"
    "/* Auto-generated by libusb-cmake */\n"
    "#ifndef LIBUSB_CONFIG_H\n"
    "#define LIBUSB_CONFIG_H\n"
    "#define DEFAULT_VISIBILITY __attribute__((visibility(\"default\")))\n"
    "#define PRINTF_FORMAT(a, b) __attribute__((__format__(__printf__, a, b)))\n"
)
if(APPLE OR UNIX)
    file(APPEND "${_LIBUSB_CONFIG_H}"
        "#define PLATFORM_POSIX 1\n"
        "#define HAVE_CLOCK_GETTIME 1\n"
        "#define HAVE_SYS_TIME_H 1\n"
        "#define THREADS_POSIX 1\n"
        "#include <pthread.h>\n"
        "typedef pthread_mutex_t usbi_mutex_t;\n"
        "typedef pthread_key_t usbi_tls_key_t;\n"
    )
    if(APPLE)
        file(APPEND "${_LIBUSB_CONFIG_H}"
            "#include <poll.h>\n"
            "typedef int usbi_os_handle_t;\n"
        )
    else()
        file(APPEND "${_LIBUSB_CONFIG_H}"
            "#include <poll.h>\n"
            "typedef int usbi_os_handle_t;\n"
            "#define HAVE_EVENTFD 1\n"
            "#define HAVE_TIMERFD 1\n"
        )
    endif()
elseif(WIN32)
    file(APPEND "${_LIBUSB_CONFIG_H}"
        "#define PLATFORM_WINDOWS 1\n"
    )
endif()
file(APPEND "${_LIBUSB_CONFIG_H}" "#endif\n")

add_library(usb-1.0-static STATIC ${LIBUSB_SOURCES})

target_include_directories(usb-1.0-static
    PUBLIC ${LIBUSB_SRC_DIR}
    PRIVATE ${LIBUSB_SRC_DIR}/os ${CMAKE_CURRENT_BINARY_DIR}
)

# Platform-specific compile definitions
if(APPLE)
    target_compile_definitions(usb-1.0-static PRIVATE
        OS_DARWIN=1
        HAVE_CLOCK_GETTIME=1
    )
elseif(UNIX)
    target_compile_definitions(usb-1.0-static PRIVATE
        OS_LINUX=1
        _GNU_SOURCE=1
        HAVE_CLOCK_GETTIME=1
        HAVE_EVENTFD=1
        HAVE_TIMERFD=1
    )
    target_include_directories(usb-1.0-static PRIVATE ${UDEV_INCLUDE_DIRS})
elseif(WIN32)
    target_compile_definitions(usb-1.0-static PRIVATE
        OS_WINDOWS=1
    )
endif()

# Suppress warnings in third-party code
target_compile_options(usb-1.0-static PRIVATE -w)

target_link_libraries(usb-1.0-static PRIVATE ${LIBUSB_PLATFORM_LIBS})
