-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
269 lines (229 loc) · 10.3 KB
/
CMakeLists.txt
File metadata and controls
269 lines (229 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
cmake_minimum_required(VERSION 3.20)
project(liblloyal VERSION 0.1.0 LANGUAGES CXX)
# =============================================================================
# liblloyal - Header-only C++20 library for llama.cpp inference wrappers
# =============================================================================
#
# This library provides type-safe, ergonomic wrappers around llama.cpp for
# multiple language bindings. All implementations are header-only with inline
# specifiers.
#
# Dependencies:
# - llama.cpp (b8369 or compatible)
# - C++20 compiler
#
# Usage:
# add_subdirectory(packages/liblloyal)
# target_link_libraries(your_target PRIVATE liblloyal::liblloyal)
#
# =============================================================================
# Configuration
# =============================================================================
# Require C++20
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# =============================================================================
# Define INTERFACE Library Target
# =============================================================================
add_library(liblloyal INTERFACE)
add_library(liblloyal::liblloyal ALIAS liblloyal)
# =============================================================================
# Include Directories
# =============================================================================
target_include_directories(liblloyal INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# =============================================================================
# llama.cpp Common Library Include Path
# =============================================================================
# When building with LLAMA_BUILD_COMMON=ON, add paths for:
# - common/*.h headers (chat.h, common.h, json-schema-to-grammar.h)
# - vendor/nlohmann/* for JSON support
if(TARGET common)
if(TARGET llama)
# Get llama.cpp source directory from the llama target
get_target_property(LLAMA_INCLUDE_DIRS llama INTERFACE_INCLUDE_DIRECTORIES)
foreach(dir ${LLAMA_INCLUDE_DIRS})
if(EXISTS "${dir}/llama.h")
get_filename_component(LLAMA_CPP_ROOT "${dir}" DIRECTORY)
target_include_directories(liblloyal INTERFACE
$<BUILD_INTERFACE:${LLAMA_CPP_ROOT}/common>
$<BUILD_INTERFACE:${LLAMA_CPP_ROOT}/vendor>
)
message(STATUS "liblloyal: Added common library includes from ${LLAMA_CPP_ROOT}")
break()
endif()
endforeach()
endif()
# Link common library so consumers get symbols for common_chat_*, json_schema_to_grammar, etc.
target_link_libraries(liblloyal INTERFACE common)
endif()
# =============================================================================
# Dependencies
# =============================================================================
# llama.cpp dependency
# Consumer must provide llama target or locate llama.cpp
if(TARGET llama)
target_link_libraries(liblloyal INTERFACE llama)
message(STATUS "liblloyal: Found llama.cpp target")
else()
message(WARNING "liblloyal: llama.cpp target not found. Consumer must provide llama target.")
endif()
# =============================================================================
# Include Path Setup for Consumers
# =============================================================================
# liblloyal headers use #include <llama/llama.h> but llama.cpp provides
# include/llama.h (flat structure). We create the expected namespace structure
# in the build directory at configure time using wrapper headers.
#
# Why wrapper headers? Cross-platform compatibility without symbol conflicts.
# - Symlinks fail on Windows (require admin/Developer Mode)
# - Copying creates duplicate definitions when llama target exports its paths
# - Wrapper headers forward-include, creating the namespace without duplication
#
# Template files: cmake/templates/{llama,ggml}.h.in
# Generated at configure time via configure_file() with @ONLY
if(TARGET llama)
# Get llama.cpp include directory from llama target
get_target_property(LLAMA_INCLUDE_DIRS llama INTERFACE_INCLUDE_DIRECTORIES)
foreach(dir ${LLAMA_INCLUDE_DIRS})
if(EXISTS "${dir}/llama.h")
set(LLAMA_CPP_INCLUDE_DIR "${dir}")
break()
endif()
endforeach()
# Get ggml include directory from ggml or ggml-base target (if exists)
# Also check relative to llama.cpp source dir as fallback
if(TARGET ggml)
get_target_property(GGML_INCLUDE_DIRS ggml INTERFACE_INCLUDE_DIRECTORIES)
foreach(dir ${GGML_INCLUDE_DIRS})
if(EXISTS "${dir}/ggml.h")
set(GGML_INCLUDE_DIR "${dir}")
break()
endif()
endforeach()
endif()
if(NOT GGML_INCLUDE_DIR AND TARGET ggml-base)
get_target_property(GGML_INCLUDE_DIRS ggml-base INTERFACE_INCLUDE_DIRECTORIES)
foreach(dir ${GGML_INCLUDE_DIRS})
if(EXISTS "${dir}/ggml.h")
set(GGML_INCLUDE_DIR "${dir}")
break()
endif()
endforeach()
endif()
# Fallback: look relative to llama.cpp include dir (ggml is sibling)
if(NOT GGML_INCLUDE_DIR AND LLAMA_CPP_INCLUDE_DIR)
# llama.h is in llama.cpp/include, ggml.h is in llama.cpp/ggml/include
get_filename_component(LLAMA_CPP_ROOT "${LLAMA_CPP_INCLUDE_DIR}" DIRECTORY)
set(GGML_FALLBACK_DIR "${LLAMA_CPP_ROOT}/ggml/include")
if(EXISTS "${GGML_FALLBACK_DIR}/ggml.h")
set(GGML_INCLUDE_DIR "${GGML_FALLBACK_DIR}")
endif()
endif()
# Create llama/ namespace with wrapper headers at configure time
if(LLAMA_CPP_INCLUDE_DIR)
set(PUBLIC_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include/llama)
file(MAKE_DIRECTORY ${PUBLIC_INCLUDE_DIR})
# Generate wrapper headers from templates
# These forward-include the actual headers, creating the llama/ namespace
# without duplicating definitions
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/llama.h.in
${PUBLIC_INCLUDE_DIR}/llama.h
@ONLY
)
if(GGML_INCLUDE_DIR)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/ggml.h.in
${PUBLIC_INCLUDE_DIR}/ggml.h
@ONLY
)
endif()
# Export build/include BEFORE llama.cpp's paths so our wrappers are found first
target_include_directories(liblloyal BEFORE INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
)
message(STATUS "liblloyal: Created llama/ include namespace at ${PUBLIC_INCLUDE_DIR}")
else()
message(WARNING "liblloyal: Could not find llama.cpp include directory. Consumers may need manual include path setup.")
endif()
endif()
# =============================================================================
# Version Check for llama.cpp
# =============================================================================
# liblloyal is tested against llama.cpp b8369
# This is a soft check - we warn but don't fail the build
if(DEFINED LLAMA_CPP_VERSION)
if(NOT LLAMA_CPP_VERSION STREQUAL "b8369")
message(WARNING
"liblloyal: Designed for llama.cpp b8369, found ${LLAMA_CPP_VERSION}. "
"API compatibility not guaranteed.")
else()
message(STATUS "liblloyal: Using recommended llama.cpp version b8369")
endif()
else()
message(STATUS
"liblloyal: LLAMA_CPP_VERSION not set. Recommended: b8369. "
"Define LLAMA_CPP_VERSION in your llama.cpp CMakeLists to enable version check.")
endif()
# =============================================================================
# Compiler Requirements
# =============================================================================
target_compile_features(liblloyal INTERFACE cxx_std_20)
# =============================================================================
# Installation (Optional - for package managers)
# =============================================================================
# Only configure install rules when liblloyal is the top-level project.
# When used via add_subdirectory(), the parent project handles installation.
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
include(GNUInstallDirs)
install(TARGETS liblloyal
EXPORT liblloyal-targets
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(DIRECTORY include/lloyal
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.hpp"
)
install(EXPORT liblloyal-targets
FILE liblloyal-targets.cmake
NAMESPACE liblloyal::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liblloyal
)
# Generate and install package config files
include(CMakePackageConfigHelpers)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/liblloyal-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/liblloyal-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liblloyal
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/liblloyal-config-version.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/liblloyal-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/liblloyal-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liblloyal
)
endif()
# =============================================================================
# Testing (Enable with -DLIBLLOYAL_BUILD_TESTS=ON)
# =============================================================================
option(LIBLLOYAL_BUILD_TESTS "Build liblloyal smoke tests" OFF)
if(LIBLLOYAL_BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
# =============================================================================
# Documentation
# =============================================================================
message(STATUS "liblloyal configured:")
message(STATUS " Version: ${PROJECT_VERSION}")
message(STATUS " C++ Standard: C++20")
message(STATUS " Include Dir: ${CMAKE_CURRENT_SOURCE_DIR}/include")
message(STATUS " Build Tests: ${LIBLLOYAL_BUILD_TESTS}")