载入中...
搜索中...
未找到
Package.cpp
浏览该文件的文档.
1#include "cmdline.h"
2#include "zip_writer.h"
3#include "common/config.h"
4#include <filesystem>
5#include <CLI11.hpp>
6#include <rang.hpp>
7
8#ifdef EVENGINE_WINDOWS
9#include <windows.h>
10#else
11#include <unistd.h>
12#endif
13
14using namespace std::filesystem;
15using namespace std;
16
17namespace eve::cmd
18{
19
20namespace {
21
22// Runtime binary name inside the SDK's bin/: eve.exe on Windows, eve elsewhere.
23#ifdef EVENGINE_WINDOWS
24constexpr const char* kEveRuntimeName = "eve.exe";
25#else
26constexpr const char* kEveRuntimeName = "eve";
27#endif
28
29bool copyFileIf(const path& src, const path& dst) {
30 error_code ec;
31 if (!exists(src, ec)) return false;
32 create_directories(dst.parent_path(), ec);
33 copy_file(src, dst, copy_options::overwrite_existing, ec);
34 return !ec;
35}
36
37// Best-effort copy of a DLL from any of the candidate source directories.
38bool copyFirst(const std::string& dll, const std::vector<path>& candidates, const path& dstDir) {
39 for (const auto& dir : candidates) {
40 path p = dir / dll;
41 if (copyFileIf(p, dstDir / dll)) return true;
42 }
43 return false;
44}
45
46// Locate the target SDK root: --sdk, EVENGINE_SDK, or next to the running binary.
47std::string resolveSdkRoot(const std::string& sdkArg) {
48 if (!sdkArg.empty() && is_directory(sdkArg)) return sdkArg;
49
50 const char* env = getenv("EVENGINE_SDK");
51 if (env && is_directory(env)) return env;
52
53 // Running from <sdk>/bin/<runtime> -> root is two directories up.
54 path exe;
55#ifdef EVENGINE_WINDOWS
56 wchar_t buf[MAX_PATH + 1] = {0};
57 if (GetModuleFileNameW(nullptr, buf, MAX_PATH) != 0) exe = path(buf);
58#else
59 char buf[4096] = {0};
60 const ssize_t n = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
61 if (n > 0) exe = path(std::string(buf, static_cast<size_t>(n)));
62#endif
63 if (!exe.empty()) {
64 path root = exe.parent_path().parent_path();
65 if (exists(root / "share" / "eve" / "TARGET_PLATFORM")) return root.string();
66 }
67 return "";
68}
69
70} // namespace
71
74 void setup(CLI::App& app, std::shared_ptr<CLI::Formatter> formatter) override {
75 auto subcmd = app.add_subcommand("package", "Package a game into a runnable game folder.");
76 subcmd->allow_extras();
77 subcmd->add_option("-o,--output", outputPath, "output folder path");
78 subcmd->add_option("--sdk", sdkPath, "target SDK root (default: auto-detect / $EVENGINE_SDK)");
79 }
80
81 int parse(CLI::App& app, Cmdline& cmd) override {
82 auto subcmd = app.get_subcommand("package");
83 if (subcmd->parsed()) {
84 string game = cmd.get_remaining(subcmd, ".");
85 int res = cmd.Package(game, outputPath, sdkPath);
86 return res;
87 }
88 return -1; // not handle
89 }
90};
91
93
94int Cmdline::Package(std::string gamePath, std::string output, std::string sdk) {
95 error_code ec;
96 if (!is_directory(gamePath, ec)) {
97 cerr << rang::fg::red << "Not a directory: " << rang::fg::reset << gamePath << endl;
98 return 1;
99 }
100
101 std::string sdkRoot = resolveSdkRoot(sdk);
102 if (sdkRoot.empty()) {
103 cerr << rang::fg::red
104 << "Cannot locate the target SDK. Pass --sdk <dir>, set $EVENGINE_SDK, "
105 "or run from <sdk>/bin/<runtime>."
106 << rang::fg::reset << endl;
107 return 2;
108 }
109
110 // Game folder name, trailing separators stripped.
111 std::string gameName = gamePath;
112 while (!gameName.empty() && (gameName.back() == '/' || gameName.back() == '\\'))
113 gameName.pop_back();
114 if (gameName.find_first_of("/\\") != string::npos)
115 gameName = std::filesystem::path(gameName).filename().string();
116 if (gameName.empty()) gameName = "game";
117
118 path outDir = output.empty() ? path(gameName + "-package") : path(output);
119 create_directories(outDir, ec);
120
121 path sdkBin = path(sdkRoot) / "bin";
122 path sdkPlat = path(sdkRoot) / "platform";
123
124 // 1. Runtime executable.
125 path runtimeSrc = sdkBin / kEveRuntimeName;
126 path runtimeDst = outDir / kEveRuntimeName;
127 if (!copyFileIf(runtimeSrc, runtimeDst)) {
128 cerr << rang::fg::red << "SDK missing " << runtimeSrc.string() << rang::fg::reset << endl;
129 return 3;
130 }
131
132#ifdef EVENGINE_WINDOWS
133 // 2. Windows runtime DLLs the executable needs (vulkan + VC CRT). Best-effort.
134 std::vector<path> crtCandidates;
135 if (exists(sdkBin)) crtCandidates.push_back(sdkBin);
136 // VC redist (version-independent glob): both release CRT and debug CRT.
137 for (const auto& msroot : {"C:/Program Files/Microsoft Visual Studio"}) {
138 path base = path(msroot);
139 if (exists(base / "18")) base = base / "18";
140 for (const auto& entry : directory_iterator(base, ec)) {
141 if (!entry.is_directory()) continue;
142 path redist = entry.path() / "Community" / "VC" / "Redist" / "MSVC";
143 if (!exists(redist)) continue;
144 for (const auto& ver : directory_iterator(redist, ec)) {
145 for (const auto& crtDir : {"x64", "debug_nonredist/x64"}) {
146 path crt = ver.path() / crtDir;
147 if (!exists(crt)) continue;
148 for (const auto& sub : directory_iterator(crt, ec)) {
149 if (!sub.is_directory()) continue;
150 const std::string n = sub.path().filename().string();
151 if (n.find("Microsoft.VC") == 0 && (n.find(".CRT") != string::npos ||
152 n.find("DebugCRT") != string::npos))
153 crtCandidates.push_back(sub.path());
154 }
155 }
156 }
157 }
158 }
159 if (exists(path("C:/Windows/System32"))) crtCandidates.push_back(path("C:/Windows/System32"));
160
161 // eve.exe links the VC runtime dynamically; bundle both release and debug sets so
162 // the package is self-contained regardless of build type.
163 for (const auto& dll : {"vulkan-1.dll", "msvcp140.dll", "msvcp140_1.dll",
164 "msvcp140_2.dll", "vcruntime140.dll", "vcruntime140_1.dll",
165 "concrt140.dll", "msvcp140d.dll", "vcruntime140d.dll",
166 "vcruntime140_1d.dll", "ucrtbased.dll", "concrt140d.dll"}) {
167 if (!copyFirst(dll, crtCandidates, outDir))
168 cerr << rang::fg::yellow << "note: runtime DLL not found (may be system-installed): "
169 << dll << rang::fg::reset << endl;
170 }
171#endif // EVENGINE_WINDOWS
172
173#ifdef EVENGINE_MACOSX
174 // 2b. macOS: bundle the runtime dylibs (Vulkan loader, zlib, ...) that the
175 // executable links from the SDK's lib/ directory, so the packaged game is
176 // self-contained next to the eve binary.
177 path sdkLib = path(sdkRoot) / "lib";
178 if (exists(sdkLib)) {
179 for (const auto& entry : directory_iterator(sdkLib, ec)) {
180 if (entry.is_regular_file() && entry.path().extension() == ".dylib")
181 copyFileIf(entry.path(), outDir / entry.path().filename());
182 }
183 ec.clear();
184 }
185#endif // EVENGINE_MACOSX
186
187 // 3. Platform packaging template (win32/linux README etc).
188 if (exists(sdkPlat)) {
189 for (const auto& entry : directory_iterator(sdkPlat, ec)) {
190 copy(entry.path(), outDir / entry.path().filename(),
191 copy_options::recursive | copy_options::overwrite_existing, ec);
192 ec.clear();
193 }
194 }
195
196 // 4. Compress the game directory into game.eve inside the package.
197 path archive = outDir / "game.eve";
198 if (!cmdline::createGameArchive(gamePath, archive)) {
199 cerr << rang::fg::red << "Failed to package game archive." << rang::fg::reset << endl;
200 return 4;
201 }
202
203 cout << rang::fg::green << "Built game package -> " << rang::fg::reset << outDir.string() << endl;
204 cout << " run: " << runtimeDst.string() << endl;
205 return 0;
206}
207
208} // namespace eve::cmd
209
glm::vec3 n
Definition Grass.cpp:64
glm::vec4 p[6]
V3 dir
Definition TreeMesh.cpp:121
命令行模块(eve.cmd):run / build / package / test / zip / dev-server 等子命令入口。
Definition cmdline.h:30
static std::string get_remaining(CLI::App *sub, std::string default_path=".")
子命令剩余位置参数。
Definition cmdline.cpp:79
int Package(std::string path, std::string output, std::string sdk)
把游戏打包为单个可执行文件 / APK。
Definition Package.cpp:94
#define CMD_REG(name)
Definition cmdline.h:92
bool createGameArchive(const std::filesystem::path &gameDir, const std::filesystem::path &outArchive)
Definition zip_writer.h:181
One eve <subcommand> handler: CLI setup + argument parsing.
Definition cmdline.h:21
void setup(CLI::App &app, std::shared_ptr< CLI::Formatter > formatter) override
Registers options on the CLI11 sub-app.
Definition Package.cpp:74
int parse(CLI::App &app, Cmdline &cmd) override
Parses arguments and runs the command; returns the exit code.
Definition Package.cpp:81