-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.mcpp
More file actions
129 lines (117 loc) · 4.43 KB
/
Copy pathbuild.mcpp
File metadata and controls
129 lines (117 loc) · 4.43 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
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iterator>
#include <sstream>
#include <stdexcept>
#include <string>
namespace fs = std::filesystem;
static std::string read_all(const fs::path & path) {
std::ifstream in(path, std::ios::binary);
if (!in) throw std::runtime_error("cannot read " + path.string());
return {std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
}
static void write_all(const fs::path & path, const std::string & value) {
fs::create_directories(path.parent_path());
std::ofstream out(path, std::ios::binary | std::ios::trunc);
out.write(value.data(), static_cast<std::streamsize>(value.size()));
if (!out) throw std::runtime_error("cannot write " + path.string());
}
static void replace_once(
std::string & value,
const std::string & marker,
const std::string & replacement
) {
auto first = value.find(marker);
if (first == std::string::npos
|| value.find(marker, first + marker.size()) != std::string::npos) {
throw std::runtime_error("expected exactly one marker: " + marker);
}
value.replace(first, marker.size(), replacement);
}
static std::string asm_quote(std::string value) {
std::string out;
for (char c : value) {
if (c == '\\' || c == '"') out.push_back('\\');
out.push_back(c);
}
return out;
}
static int validate_features() {
const char * raw = std::getenv("MCPP_FEATURES");
if (!raw || *raw == '\0') return 0;
std::istringstream input(raw);
std::string feature;
while (std::getline(input, feature, ',')) {
if (feature.empty()
|| feature == "backend-cpu"
|| feature == "backend-metal") {
continue;
}
std::fprintf(
stderr,
"mcpplibs:llamacpp: unsupported feature '%s' "
"(supported features: backend-cpu, backend-metal)\n",
feature.c_str()
);
return 2;
}
return 0;
}
int main() try {
if (int result = validate_features(); result != 0) return result;
const char * enabled = std::getenv("MCPP_FEATURE_BACKEND_METAL");
if (!enabled || std::string(enabled) != "1") return 0;
const char * os = std::getenv("MCPP_TARGET_OS");
const char * arch = std::getenv("MCPP_TARGET_ARCH");
const char * manifest = std::getenv("MCPP_MANIFEST_DIR");
const char * out_env = std::getenv("MCPP_OUT_DIR");
if (!os || std::string(os) != "macos") {
std::fprintf(stderr, "mcpplibs:llamacpp requires target_os=macos\n");
return 2;
}
if (!arch || std::string(arch) != "aarch64") {
std::fprintf(stderr, "mcpplibs:llamacpp requires target_arch=aarch64\n");
return 2;
}
if (!manifest || !out_env) {
std::fprintf(
stderr,
"mcpplibs:llamacpp requires MCPP_MANIFEST_DIR and MCPP_OUT_DIR\n"
);
return 2;
}
const fs::path root = fs::path(manifest) / "third_party/llama.cpp";
if (!fs::exists(root / "ggml/src/ggml-common.h")) {
throw std::runtime_error("vendored llama.cpp source root not found");
}
const fs::path common = root / "ggml/src/ggml-common.h";
const fs::path metal = root / "ggml/src/ggml-metal/ggml-metal.metal";
const fs::path impl = root / "ggml/src/ggml-metal/ggml-metal-impl.h";
const fs::path out = out_env;
const fs::path merged = out / "ggml-metal-embed.metal";
const fs::path assembly = out / "ggml-metal-embed.s";
std::string source = read_all(metal);
replace_once(source, "__embed_ggml-common.h__", read_all(common));
replace_once(source, "#include \"ggml-metal-impl.h\"", read_all(impl));
write_all(merged, source);
std::ostringstream body;
body << ".section __DATA,__ggml_metallib\n"
<< ".globl _ggml_metallib_start\n"
<< "_ggml_metallib_start:\n"
<< ".incbin \"" << asm_quote(merged.string()) << "\"\n"
<< ".globl _ggml_metallib_end\n"
<< "_ggml_metallib_end:\n";
write_all(assembly, body.str());
std::printf("mcpp:generated=%s\n", assembly.string().c_str());
std::printf("mcpp:cfg=GGML_METAL_EMBED_LIBRARY\n");
for (const fs::path & input : {common, metal, impl}) {
std::printf("mcpp:rerun-if-changed=%s\n", input.string().c_str());
}
std::fflush(stdout);
return 0;
} catch (const std::exception & error) {
std::fprintf(stderr, "mcpplibs:llamacpp build.mcpp: %s\n", error.what());
return 1;
}