diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d4bcf45f5..5a74ba1e35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,7 @@ option(LLAMA_BUILD_SERVER "llama: build server example" option(LLAMA_BUILD_APP "llama: build the unified binary" ${LLAMA_STANDALONE}) option(LLAMA_BUILD_UI "llama: build the embedded Web UI for server" OFF) option(LLAMA_USE_PREBUILT_UI "llama: use prebuilt UI from HF Bucket when available" ON) +option(LLAMA_CONNECT "llama: include the llama-connect tool (downloads a prebuilt binary)" OFF) option(LLAMA_TOOLS_INSTALL "llama: install tools" ${LLAMA_TOOLS_INSTALL_DEFAULT}) option(LLAMA_TESTS_INSTALL "llama: install tests" ON) diff --git a/scripts/connect-download.cmake b/scripts/connect-download.cmake new file mode 100644 index 0000000000..ce11479210 --- /dev/null +++ b/scripts/connect-download.cmake @@ -0,0 +1,76 @@ +# download the prebuilt llama-connect binary for the given platform +# the release assets are made by: https://github.com/ggml-org/llama-connect/blob/master/.github/workflows/build.yml + +cmake_minimum_required(VERSION 3.18) + +set(REPO "" CACHE STRING "GitHub repository to download from (owner/name)") +set(VERSION "" CACHE STRING "Release tag to download, or 'latest'") +set(PLATFORM "" CACHE STRING "Platform suffix of the release asset (ex: linux-x64)") +set(OUT_DIR "" CACHE STRING "Directory to place the binary into") +set(WORK_DIR "" CACHE STRING "Scratch directory used for the download") + +if (PLATFORM MATCHES "^win-") + set(ASSET "llama-connect-${PLATFORM}.zip") + set(BINARY "llama-connect.exe") +else() + set(ASSET "llama-connect-${PLATFORM}.tar.gz") + set(BINARY "llama-connect") +endif() + +if (VERSION STREQUAL "latest") + set(URL "https://github.com/${REPO}/releases/latest/download/${ASSET}") +else() + set(URL "https://github.com/${REPO}/releases/download/${VERSION}/${ASSET}") +endif() + +set(DST "${OUT_DIR}/${BINARY}") +set(ARCHIVE "${WORK_DIR}/${ASSET}") +set(STAMP "${WORK_DIR}/${BINARY}.url") + +# skip if already downloaded from the same URL +if (EXISTS "${DST}" AND EXISTS "${STAMP}") + file(READ "${STAMP}" prev_url) + if (prev_url STREQUAL "${URL}") + return() + endif() +endif() + +file(REMOVE "${STAMP}") +file(MAKE_DIRECTORY "${WORK_DIR}") + +message(STATUS "llama-connect: downloading ${URL}") + +file(DOWNLOAD "${URL}" "${ARCHIVE}" STATUS status TLS_VERIFY ON) + +list(GET status 0 code) +list(GET status 1 msg) + +if (NOT code EQUAL 0) + file(REMOVE "${ARCHIVE}") + message(FATAL_ERROR + "llama-connect: failed to download ${URL} (${code}: ${msg})\n" + " use -DLLAMA_CONNECT_VERSION= to select another release, " + "or -DLLAMA_CONNECT=OFF to skip this tool") +endif() + +set(EXTRACT_DIR "${WORK_DIR}/extract") + +file(REMOVE_RECURSE "${EXTRACT_DIR}") +file(MAKE_DIRECTORY "${EXTRACT_DIR}") +file(ARCHIVE_EXTRACT INPUT "${ARCHIVE}" DESTINATION "${EXTRACT_DIR}") + +if (NOT EXISTS "${EXTRACT_DIR}/${BINARY}") + message(FATAL_ERROR "llama-connect: ${ASSET} does not contain ${BINARY}") +endif() + +file(MAKE_DIRECTORY "${OUT_DIR}") +file(COPY "${EXTRACT_DIR}/${BINARY}" DESTINATION "${OUT_DIR}" + FILE_PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE +) + +file(WRITE "${STAMP}" "${URL}") + +message(STATUS "llama-connect: ready at ${DST}") diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index c8ad1db436..6a6592c7bf 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -32,6 +32,9 @@ else() if (GGML_RPC) add_subdirectory(rpc) endif() + if (LLAMA_CONNECT) + add_subdirectory(connect) + endif() if (NOT GGML_BACKEND_DL AND GGML_CPU) # these tools use backends directly (no dynamic loading) and depend on CPU backend symbols add_subdirectory(cvector-generator) diff --git a/tools/connect/CMakeLists.txt b/tools/connect/CMakeLists.txt new file mode 100644 index 0000000000..c36f7642bf --- /dev/null +++ b/tools/connect/CMakeLists.txt @@ -0,0 +1,81 @@ +# llama-connect is developed in a separate repo, nothing is compiled here +# we only download the prebuilt binary, see scripts/connect-download.cmake + +set(TARGET llama-connect) + +set(LLAMA_CONNECT_REPO "ggml-org/llama-connect" CACHE STRING "llama-connect: GitHub repository to download from") +set(LLAMA_CONNECT_VERSION "latest" CACHE STRING "llama-connect: release tag to download (ex: v0.0.1), or 'latest'") + +# map the target platform to the release asset name +set(LLAMA_CONNECT_PLATFORM "") + +if (APPLE) + set(_arch "${CMAKE_SYSTEM_PROCESSOR}") + if (CMAKE_OSX_ARCHITECTURES) + list(LENGTH CMAKE_OSX_ARCHITECTURES _narch) + if (_narch EQUAL 1) + set(_arch "${CMAKE_OSX_ARCHITECTURES}") + else() + set(_arch "universal") # no such asset, so the tool is skipped below + endif() + endif() + + if (_arch MATCHES "^(arm64|aarch64)$") + set(LLAMA_CONNECT_PLATFORM "macos-arm64") + elseif (_arch MATCHES "^(x86_64|AMD64|amd64|x64)$") + set(LLAMA_CONNECT_PLATFORM "macos-x64") + endif() +elseif (WIN32) + # with Visual Studio generators, the target arch comes from -A + set(_arch "${CMAKE_SYSTEM_PROCESSOR}") + if (CMAKE_GENERATOR_PLATFORM) + set(_arch "${CMAKE_GENERATOR_PLATFORM}") + endif() + + if (_arch MATCHES "^(x86_64|AMD64|amd64|x64)$") + set(LLAMA_CONNECT_PLATFORM "win-x64") + endif() +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64|x64)$") + set(LLAMA_CONNECT_PLATFORM "linux-x64") + elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)$") + set(LLAMA_CONNECT_PLATFORM "linux-arm64") + endif() +endif() + +if (LLAMA_CONNECT_PLATFORM STREQUAL "") + message(WARNING "llama-connect: no prebuilt binary for ${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}, skipping") + return() +endif() + +if (LLAMA_CONNECT_PLATFORM MATCHES "^win-") + set(LLAMA_CONNECT_BINARY "llama-connect.exe") +else() + set(LLAMA_CONNECT_BINARY "llama-connect") +endif() + +# multi-config generators put the binaries in a per-config subdir +get_property(LLAMA_CONNECT_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if (LLAMA_CONNECT_MULTI_CONFIG) + set(LLAMA_CONNECT_OUT_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$") +else() + set(LLAMA_CONNECT_OUT_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") +endif() + +# the script is a no-op if the binary is already downloaded +add_custom_target(${TARGET} ALL + BYPRODUCTS "${LLAMA_CONNECT_OUT_DIR}/${LLAMA_CONNECT_BINARY}" + COMMAND ${CMAKE_COMMAND} + "-DREPO=${LLAMA_CONNECT_REPO}" + "-DVERSION=${LLAMA_CONNECT_VERSION}" + "-DPLATFORM=${LLAMA_CONNECT_PLATFORM}" + "-DOUT_DIR=${LLAMA_CONNECT_OUT_DIR}" + "-DWORK_DIR=${CMAKE_CURRENT_BINARY_DIR}" + -P "${PROJECT_SOURCE_DIR}/scripts/connect-download.cmake" + COMMENT "Downloading llama-connect (${LLAMA_CONNECT_PLATFORM}, ${LLAMA_CONNECT_VERSION})" + VERBATIM +) + +if (LLAMA_TOOLS_INSTALL) + install(PROGRAMS "${LLAMA_CONNECT_OUT_DIR}/${LLAMA_CONNECT_BINARY}" TYPE BIN) +endif()