Skip to content

Commit e6b7caa

Browse files
The gemma.cpp Authorscopybara-github
The gemma.cpp Authors
authored andcommitted
Add C API and C# interop files
This change adds a basic C API that allows access to Gemma functionality from other programming languages. The functionality is exposed via a shared library (DLL on Windows), with C++ interfaces and a basic C# interop wrapper included. To build the DLL, use the `windows-dll` preset, which includes the C and C++ sources as follows: ``` cmake --preset windows-dll cmake --build --config Release --preset windows-dll -j 4 ``` This should generate a `gemma.dll` in `<build-dir>/Release`. To build for non-Windows, the appropriate C++ DLL linking will need to be done to generate a shared library for the target OS. PiperOrigin-RevId: 747940577
1 parent 87a658b commit e6b7caa

11 files changed

+1327
-10
lines changed

BUILD.bazel

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,40 @@ cc_library(
428428
],
429429
)
430430

431+
cc_library(
432+
name = "gemma_shared_lib",
433+
srcs = [
434+
"gemma/bindings/c_api.cc",
435+
"gemma/bindings/context.cc",
436+
],
437+
hdrs = [
438+
"gemma/bindings/c_api.h",
439+
"gemma/bindings/context.h",
440+
],
441+
exec_properties = {
442+
# Avoid linker OOMs when building with sanitizer instrumentation.
443+
"mem": "28g",
444+
},
445+
deps = [
446+
":allocator",
447+
":basics",
448+
":benchmark_helper",
449+
":common",
450+
":gemma_args",
451+
":gemma_lib",
452+
":kv_cache",
453+
":mat",
454+
":ops",
455+
":threading",
456+
":threading_context",
457+
":tokenizer",
458+
":weights",
459+
"//compression:shared",
460+
"//paligemma:image",
461+
"@highway//:hwy",
462+
],
463+
)
464+
431465
cc_library(
432466
name = "cross_entropy",
433467
srcs = ["evals/cross_entropy.cc"],
@@ -465,6 +499,7 @@ cc_library(
465499
":gemma_lib",
466500
":ops",
467501
":threading_context",
502+
":tokenizer",
468503
"@google_benchmark//:benchmark",
469504
"//compression:compress",
470505
"@highway//:hwy",
@@ -522,6 +557,7 @@ cc_binary(
522557
":gemma_lib",
523558
":ops",
524559
":threading_context",
560+
":tokenizer",
525561
"//compression:shared",
526562
"//paligemma:image",
527563
"@highway//:hwy",

CMakeLists.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ set(BENCHMARK_ENABLE_GTEST_TESTS OFF)
3939
FetchContent_Declare(benchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.8.2 EXCLUDE_FROM_ALL)
4040
FetchContent_MakeAvailable(benchmark)
4141

42+
# Base source files
4243
set(SOURCES
4344
compression/blob_store.cc
4445
compression/blob_store.h
@@ -115,6 +116,17 @@ set(SOURCES
115116
util/topology.h
116117
)
117118

119+
# Add C API sources only when building DLL
120+
if(BUILD_GEMMA_DLL)
121+
list(APPEND SOURCES
122+
gemma/bindings/context.h
123+
gemma/bindings/context.cc
124+
gemma/bindings/c_api.h
125+
gemma/bindings/c_api.cc
126+
)
127+
message(STATUS "Including C API files for DLL build")
128+
endif()
129+
118130
if(NOT CMAKE_BUILD_TYPE)
119131
set(CMAKE_BUILD_TYPE "Release")
120132
endif()
@@ -134,6 +146,33 @@ target_compile_definitions(libgemma PRIVATE $<$<PLATFORM_ID:Windows>:_CRT_SECURE
134146
target_compile_options(libgemma PRIVATE $<$<PLATFORM_ID:Windows>:-Wno-deprecated-declarations>)
135147
install(TARGETS libgemma DESTINATION lib)
136148

149+
# Shared library target for C# interop
150+
if(BUILD_GEMMA_DLL)
151+
add_library(gemma_shared SHARED ${SOURCES})
152+
set_property(TARGET gemma_shared PROPERTY CXX_STANDARD 17)
153+
set_target_properties(gemma_shared PROPERTIES
154+
PREFIX ""
155+
OUTPUT_NAME "gemma"
156+
)
157+
set_property(TARGET gemma_shared PROPERTY POSITION_INDEPENDENT_CODE ON)
158+
target_include_directories(gemma_shared PUBLIC ./)
159+
target_link_libraries(gemma_shared PRIVATE
160+
$<LINK_LIBRARY:WHOLE_ARCHIVE,hwy>
161+
$<LINK_LIBRARY:WHOLE_ARCHIVE,hwy_contrib>
162+
$<LINK_LIBRARY:WHOLE_ARCHIVE,sentencepiece-static>
163+
)
164+
target_include_directories(gemma_shared PUBLIC ${sentencepiece_SOURCE_DIR})
165+
target_compile_definitions(gemma_shared
166+
PRIVATE
167+
GEMMA_EXPORTS
168+
$<$<PLATFORM_ID:Windows>:_CRT_SECURE_NO_WARNINGS NOMINMAX>
169+
)
170+
target_compile_options(gemma_shared PRIVATE $<$<PLATFORM_ID:Windows>:-Wno-deprecated-declarations>)
171+
install(TARGETS gemma_shared DESTINATION lib)
172+
install(FILES gemma/c_api.h DESTINATION include/gemma)
173+
install(FILES gemma/GemmaInterop.cs DESTINATION include/gemma)
174+
endif()
175+
137176
# Executable Target
138177

139178
add_executable(gemma gemma/run.cc)

CMakePresets.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,24 @@
3131
"lhs": "${hostSystemName}",
3232
"rhs": "Windows"
3333
}
34+
},
35+
{
36+
"name": "windows-dll",
37+
"inherits": "__defaults__",
38+
"displayName": "Windows DLL",
39+
"description": "Visual Studio 2022 with Clang/LLVM frontend (DLL build)",
40+
"generator": "Visual Studio 17 2022",
41+
"toolset": "ClangCL",
42+
"condition": {
43+
"type": "equals",
44+
"lhs": "${hostSystemName}",
45+
"rhs": "Windows"
46+
},
47+
"cacheVariables": {
48+
"BUILD_SHARED_LIBS": "OFF",
49+
"CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS": "ON",
50+
"BUILD_GEMMA_DLL": "ON"
51+
}
3452
}
3553
],
3654
"buildPresets": [
@@ -54,6 +72,15 @@
5472
"displayName": "Windows",
5573
"configuration": "Release",
5674
"configurePreset": "windows"
75+
},
76+
{
77+
"name": "windows-dll",
78+
"displayName": "Windows DLL",
79+
"configuration": "Release",
80+
"configurePreset": "windows-dll",
81+
"targets": [
82+
"gemma_shared"
83+
]
5784
}
5885
]
5986
}

evals/benchmark_helper.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include "gemma/gemma.h"
2727
#include "gemma/gemma_args.h"
28+
#include "gemma/tokenizer.h" // WrapAndTokenize
2829
#include "ops/matmul.h"
2930
#include "util/threading_context.h"
3031
#include "hwy/base.h"
@@ -54,8 +55,9 @@ class GemmaEnv {
5455
size_t MaxGeneratedTokens() const {
5556
return runtime_config_.max_generated_tokens;
5657
}
57-
void SetMaxGeneratedTokens(size_t max_generated_tokens) {
58-
runtime_config_.max_generated_tokens = max_generated_tokens;
58+
void SetMaxGeneratedTokens(int max_generated_tokens) {
59+
runtime_config_.max_generated_tokens =
60+
static_cast<size_t>(max_generated_tokens);
5961
}
6062

6163
std::vector<int> Tokenize(const std::string& input) const {

0 commit comments

Comments
 (0)