封装动态库并调用

一、极简 runtime 库调用

用 C 语言写一个极简 runtime 库 → 编译成 动态库(.so / .dll) → 写主程序调用它。


1. 项目结构

复制代码
./
├── runtime.c       # 动态库源码
├── runtime.h       # 头文件
└── main.c          # 调用动态库的主程序

2. 代码文件

runtime.h

c 复制代码
#ifndef RUNTIME_H
#define RUNTIME_H

// 导出函数(Windows 需要 __declspec(dllexport))
#if _WIN32
#define API __declspec(dllexport)
#else
#define API
#endif

// 简单 runtime 函数:计算 a + b
API int runtime_add(int a, int b);

// runtime 版本信息
API const char* runtime_version(void);

#endif

runtime.c

c 复制代码
#include "runtime.h"

int runtime_add(int a, int b) {
    return a + b;
}

const char* runtime_version(void) {
    return "runtime v1.0.0 (dynamic library)";
}

main.c(调用方)

c 复制代码
#include <stdio.h>
#include "runtime.h"

int main() {
    printf("call from dynamic library:\n");

    int res = runtime_add(100, 200);
    printf("100 + 200 = %d\n", res);

    printf("version: %s\n", runtime_version());

    return 0;
}

3. 编译与运行

Linux / macOS

① 编译动态库
bash 复制代码
gcc -fPIC -shared runtime.c -o libruntime.so
② 编译主程序并链接动态库
bash 复制代码
gcc main.c -L. -lruntime -o main
③ 运行

Linux:

bash 复制代码
LD_LIBRARY_PATH=. ./main

macOS:

bash 复制代码
DYLD_LIBRARY_PATH=. ./main

Windows(MinGW gcc)

① 编译 DLL
bash 复制代码
gcc -shared runtime.c -o runtime.dll -Wl,--out-implib=libruntime.a
② 编译主程序
bash 复制代码
gcc main.c -L. -lruntime -o main.exe
③ 运行
bash 复制代码
main.exe

4. 预期输出

复制代码
call from dynamic library:
100 + 200 = 300
version: runtime v1.0.0 (dynamic library)

二、工程化runtime库调用

  • 分成两个独立项目:Runtime 动态库 + App 调用程序
  • 带 CMake 构建(工程化标准)
  • 跨平台:Linux / Windows / macOS 通用
  • 包含命名空间、版本、导出宏、异常、CMake install 等工程化内容
  • 动态链接(.so / .dll / .dylib)

完整项目结构

复制代码
project/
├── CMakeLists.txt          # 顶层 CMake
├── runtime/                # 动态库工程
│   ├── CMakeLists.txt
│   ├── include/
│   │   └── runtime/
│   │       ├── Runtime.h
│   │       └── Version.h
│   └── src/
│       ├── Runtime.cpp
│       └── Version.cpp
└── app/                    # 调用方程序
    ├── CMakeLists.txt
    └── src/
        └── main.cpp

1 顶层 CMakeLists.txt

cmake 复制代码
cmake_minimum_required(VERSION 3.14)
project(DynamicRuntimeDemo CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# 子模块
add_subdirectory(runtime)
add_subdirectory(app)

2 runtime 库部分

runtime/CMakeLists.txt

cmake 复制代码
add_library(runtime SHARED)

target_include_directories(runtime
PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

target_sources(runtime
PRIVATE
    src/Runtime.cpp
    src/Version.cpp
)

# 导出宏
target_compile_definitions(runtime
PRIVATE
    RUNTIME_EXPORT
)

runtime/include/runtime/Version.h

cpp 复制代码
#pragma once

#include "runtime/Platform.h"

namespace runtime {

RUNTIME_API const char* version();
RUNTIME_API int majorVersion();
RUNTIME_API int minorVersion();

}

runtime/include/runtime/Runtime.h

cpp 复制代码
#pragma once

#include "runtime/Platform.h"
#include <string>

namespace runtime {

// 核心运行时类
class RUNTIME_API Runtime {
public:
    Runtime();
    ~Runtime();

    // 示例功能
    int add(int a, int b) const;
    std::string greet(const std::string& name) const;

    // 禁止拷贝移动,典型库设计
    Runtime(const Runtime&) = delete;
    Runtime& operator=(const Runtime&) = delete;
    Runtime(Runtime&&) = delete;
    Runtime& operator=(Runtime&&) = delete;
};

}

runtime/include/runtime/Platform.h

cpp 复制代码
#pragma once

#if defined(_WIN32)
    #ifdef RUNTIME_EXPORT
        #define RUNTIME_API __declspec(dllexport)
    #else
        #define RUNTIME_API __declspec(dllimport)
    #endif
#else
    #define RUNTIME_API __attribute__((visibility("default")))
#endif

runtime/src/Version.cpp

cpp 复制代码
#include "runtime/Version.h"

namespace runtime {

const char* version() {
    return "1.0.0";
}

int majorVersion() {
    return 1;
}

int minorVersion() {
    return 0;
}

}

runtime/src/Runtime.cpp

cpp 复制代码
#include "runtime/Runtime.h"
#include <iostream>

namespace runtime {

Runtime::Runtime() {
    std::cout << "[Runtime] construct" << std::endl;
}

Runtime::~Runtime() {
    std::cout << "[Runtime] destruct" << std::endl;
}

int Runtime::add(int a, int b) const {
    return a + b;
}

std::string Runtime::greet(const std::string& name) const {
    return "Hello, " + name + " from runtime dynamic library!";
}

}

3 app 调用程序部分

app/CMakeLists.txt

cmake 复制代码
add_executable(app src/main.cpp)

target_link_libraries(app
PRIVATE
    runtime
)

app/src/main.cpp

cpp 复制代码
#include <iostream>
#include "runtime/Runtime.h"
#include "runtime/Version.h"

int main() {
    std::cout << "App start, runtime version: "
              << runtime::version() << std::endl;

    runtime::Runtime rt;

    int sum = rt.add(123, 456);
    std::cout << "123 + 456 = " << sum << std::endl;

    auto msg = rt.greet("User");
    std::cout << msg << std::endl;

    return 0;
}

4 编译运行(通用)

在项目根目录:

Linux / macOS

bash 复制代码
mkdir build && cd build
cmake ..
make -j8

运行:

bash 复制代码
./app

Windows (Visual Studio)

bash 复制代码
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022"

然后打开 sln 编译,运行 app.exe


5 典型输出

复制代码
App start, runtime version: 1.0.0
[Runtime] construct
123 + 456 = 579
Hello, User from runtime dynamic library!
[Runtime] destruct

三、runtime源码分离的动态库调用方案

完整项目结构(你本地)

复制代码
RuntimeSDK/
├── CMakeLists.txt          # 编译动态库(你自己用)
├── include/                # 对外公开 → 发给客户
│   └── Runtime.h
└── src/                    # 内部实现 → 绝不发给客户
    ├── Runtime.cpp
    └── Version.cpp

客户项目

复制代码
ClientApp/
├── include/Runtime.h
├── lib/runtime.lib
└── bin/runtime.dll

1)include/Runtime.h (对外接口,客户可见)

cpp 复制代码
#pragma once

#if defined(_WIN32)
    #ifdef RUNTIME_EXPORT
        #define RUNTIME_API __declspec(dllexport)
    #else
        #define RUNTIME_API __declspec(dllimport)
    #endif
#else
    #define RUNTIME_API __attribute__((visibility("default")))
#endif

// ###########################
// 客户只能看到这些接口!
// ###########################

#ifdef __cplusplus
extern "C" {
#endif

// 初始化
RUNTIME_API bool Runtime_Init();

// 获取版本号
RUNTIME_API const char* Runtime_GetVersion();

// 业务功能
RUNTIME_API int Runtime_Calculate(int a, int b);

// 反初始化
RUNTIME_API void Runtime_Shutdown();

#ifdef __cplusplus
}
#endif

2)src/Version.cpp (内部实现,客户不可见)

cpp 复制代码
#include "Runtime.h"

const char* Runtime_GetVersion()
{
    // 客户绝对看不到这个实现
    return "Runtime SDK v2026.04.01 | Licensed to Client";
}

3)src/Runtime.cpp (内部实现,客户不可见)

cpp 复制代码
#include "Runtime.h"
#include <iostream>

static bool g_isInitialized = false;

bool Runtime_Init()
{
    if (g_isInitialized)
        return true;

    // 客户看不到你的内部逻辑
    std::cout << "[Runtime] 初始化成功(机密代码)" << std::endl;
    g_isInitialized = true;
    return true;
}

int Runtime_Calculate(int a, int b)
{
    // 核心算法,客户看不到
    return a * 100 + b;
}

void Runtime_Shutdown()
{
    g_isInitialized = false;
    std::cout << "[Runtime] 已关闭" << std::endl;
}

4)CMakeLists.txt (编译 DLL 用)

cmake 复制代码
cmake_minimum_required(VERSION 3.14)
project(RuntimeSDK CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# 生成动态库
add_library(runtime SHARED
    src/Runtime.cpp
    src/Version.cpp
)

# 公开头文件
target_include_directories(runtime
PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Windows 导出符号
target_compile_definitions(runtime
PRIVATE
    RUNTIME_EXPORT
)

# 输出目录(方便打包给客户)
set_target_properties(runtime PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)

5)客户使用的代码(main.cpp)

客户完全没有 .cpp 文件,只有头文件 + lib + dll。

cpp 复制代码
#include <iostream>
#include "Runtime.h"

int main()
{
    Runtime_Init();

    std::cout << "版本:" << Runtime_GetVersion() << std::endl;

    int result = Runtime_Calculate(10, 20);
    std::cout << "计算结果:" << result << std::endl;

    Runtime_Shutdown();
    return 0;
}

6)客户的 CMakeLists.txt(只链接二进制)

cmake 复制代码
cmake_minimum_required(VERSION 3.14)
project(ClientApp CXX)

set(CMAKE_CXX_STANDARD 17)

add_executable(app main.cpp)

# 客户只包含头文件
target_include_directories(app PRIVATE ./include)

# 客户只链接二进制 lib(无源码)
target_link_directories(app PRIVATE ./lib)
target_link_libraries(app PRIVATE runtime.lib)

四、含日志/加密/多线程/打包Runtime SDK

1、整体说明

方案包含:Runtime SDK(你本地编译,不泄露源码)+ 客户调用工程(仅含接口/二进制,无实现),额外完善:

  • 日志功能:分级日志(DEBUG/INFO/ERROR),输出到文件+控制台,客户可配置日志级别

  • 错误码:自定义错误码体系,接口返回错误码,配套错误信息查询

  • 加密:核心接口参数加密(AES简单加密,可替换为你的加密算法)

  • 类接口:新增C++类接口(兼容原有C接口),更符合面向对象开发

  • 多线程安全:内部加锁,支持多线程并发调用接口

  • 自动打包脚本:CMake自动打包SDK(头文件+lib+dll+说明文档),直接发给客户

你本地仅保留SDK源码,客户仅获取打包后的二进制资源,完全看不到实现。

2、Runtime SDK工程

2.1 工程目录结构

plain 复制代码
RuntimeSDK/
├── CMakeLists.txt          # 编译+自动打包(你自己用)
├── include/                # 对外公开接口(发给客户)
│   └── Runtime.h
├── src/                    # 内部实现(绝不发给客户)
│   ├── Runtime.cpp
│   ├── Version.cpp
│   ├── Log.cpp             # 日志实现
│   ├── Encrypt.cpp         # 加密实现
│   └── ErrorCode.cpp       # 错误码实现
└── script/                 # 自动打包脚本(CMake调用)
    └── pack_sdk.cmake

2.2 公开接口(include/Runtime.h,客户可见)

cpp 复制代码
#pragma once

#include <cstdint>
#include <string>

// 跨平台导出/导入宏
#if defined(_WIN32)
    #ifdef RUNTIME_EXPORT
        #define RUNTIME_API __declspec(dllexport)
    #else
        #define RUNTIME_API __declspec(dllimport)
    #endif
#else
    #define RUNTIME_API __attribute__((visibility("default")))
#endif

// ###########################
// 1. 错误码定义(客户可见,用于排查问题)
// ###########################
typedef enum {
    RUNTIME_SUCCESS = 0,        // 成功
    RUNTIME_ERROR_UNINIT = 1,   // 未初始化
    RUNTIME_ERROR_PARAM = 2,    // 参数错误
    RUNTIME_ERROR_ENCRYPT = 3,  // 加密/解密失败
    RUNTIME_ERROR_THREAD = 4,   // 线程安全错误
    RUNTIME_ERROR_UNKNOWN = 99  // 未知错误
} Runtime_ErrorCode;

// ###########################
// 2. 日志级别(客户可配置)
// ###########################
typedef enum {
    RUNTIME_LOG_DEBUG = 0,      // 调试日志(仅开发用)
    RUNTIME_LOG_INFO = 1,       // 信息日志(正常运行)
    RUNTIME_LOG_ERROR = 2       // 错误日志(异常情况)
} Runtime_LogLevel;

// ###########################
// 3. C接口(兼容C/C++,稳定通用)
// ###########################
#ifdef __cplusplus
extern "C" {
#endif

// 初始化(可配置日志级别、日志路径)
// 参数:logLevel-日志级别,logPath-日志文件路径(NULL则默认当前目录)
// 返回:错误码
RUNTIME_API Runtime_ErrorCode Runtime_Init(Runtime_LogLevel logLevel, const char* logPath);

// 获取版本号
RUNTIME_API const char* Runtime_GetVersion();

// 业务计算(参数加密传输)
// 参数:a-加密后的整数a,b-加密后的整数b,key-加密密钥(长度16)
// 返回:加密后的计算结果,失败返回-1
RUNTIME_API int Runtime_Calculate(int a, int b, const char* key);

// 错误码转错误信息
RUNTIME_API const char* Runtime_GetErrorMsg(Runtime_ErrorCode errCode);

// 反初始化
RUNTIME_API void Runtime_Shutdown();

#ifdef __cplusplus
}
#endif

// ###########################
// 4. C++类接口(面向对象,客户可直接实例化调用)
// ###########################
#ifdef __cplusplus
class RUNTIME_API Runtime {
public:
    // 构造函数(自动初始化,默认日志级别INFO)
    Runtime();
    // 带参数构造(自定义日志级别和路径)
    Runtime(Runtime_LogLevel logLevel, const std::string& logPath);
    // 析构函数(自动反初始化)
    ~Runtime();

    // 获取版本号
    std::string getVersion() const;

    // 业务计算(参数加密,密钥默认"RuntimeSDK202604")
    int calculate(int a, int b, const std::string& key = "RuntimeSDK202604");

    // 获取最后一次错误码
    Runtime_ErrorCode getLastError() const;

    // 获取最后一次错误信息
    std::string getLastErrorMsg() const;

private:
    // 私有成员(客户看不到实现,隐藏内部状态)
    class Impl;
    Impl* m_impl; // 指针隐藏实现(PIMPL模式)
};
#endif

2.3 内部实现(src目录,客户不可见)

2.3.1 src/Version.cpp(版本实现)
cpp 复制代码
#include "Runtime.h"

const char* Runtime_GetVersion() {
    // 客户看不到的版本实现,可自定义版本规则
    return "Runtime SDK v2026.04.01 | Licensed to Client | 支持加密+多线程";
}

#ifdef __cplusplus
std::string Runtime::getVersion() const {
    return Runtime_GetVersion();
}
#endif
2.3.2 src/Log.cpp(日志实现,分级+文件+控制台)
cpp 复制代码
#include "Runtime.h"
#include <iostream>
#include <fstream>
#include <ctime>
#include <mutex>

// 全局日志配置
static Runtime_LogLevel g_logLevel = RUNTIME_LOG_INFO;
static std::string g_logPath = "runtime.log";
static std::mutex g_logMutex; // 日志锁,保证多线程安全

// 日志时间格式化
static std::string getCurrentTime() {
    time_t now = time(nullptr);
    struct tm tm = *localtime(&now);
    char buf[64];
    snprintf(buf, sizeof(buf), "[%04d-%02d-%02d %02d:%02d:%02d]",
             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
             tm.tm_hour, tm.tm_min, tm.tm_sec);
    return buf;
}

// 日志输出(内部函数,客户看不到)
void logOutput(Runtime_LogLevel level, const char* msg) {
    if (level < g_logLevel) return;

    std::lock_guard<std::mutex> lock(g_logMutex); // 多线程加锁

    // 日志级别字符串
    const char* levelStr = nullptr;
    switch (level) {
        case RUNTIME_LOG_DEBUG: levelStr = "DEBUG"; break;
        case RUNTIME_LOG_INFO:  levelStr = "INFO";  break;
        case RUNTIME_LOG_ERROR: levelStr = "ERROR"; break;
        default: levelStr = "UNKNOWN";
    }

    // 控制台输出
    std::cout << getCurrentTime() << " [" << levelStr << "] " << msg << std::endl;

    // 文件输出
    std::ofstream logFile(g_logPath, std::ios::app);
    if (logFile.is_open()) {
        logFile << getCurrentTime() << " [" << levelStr << "] " << msg << std::endl;
        logFile.close();
    }
}

// 对外提供的日志配置(内部调用)
void setLogConfig(Runtime_LogLevel level, const char* path) {
    g_logLevel = level;
    if (path != nullptr) {
        g_logPath = path;
    }
    logOutput(RUNTIME_LOG_INFO, "日志配置完成,日志路径:");
    logOutput(RUNTIME_LOG_INFO, g_logPath.c_str());
}
2.3.3 src/Encrypt.cpp(AES加密实现,简化版,可替换)
cpp 复制代码
#include "Runtime.h"
#include <cstring>
#include <mutex>

// AES简化加密(核心加密逻辑,客户看不到,可替换为你的加密算法)
// 此处为演示,实际商用建议用成熟加密库(如OpenSSL)
static std::mutex g_encryptMutex; // 加密锁,多线程安全

// 简单异或加密(模拟AES,实际可替换)
static int encryptData(int data, const char* key) {
    if (key == nullptr || strlen(key) != 16) {
        logOutput(RUNTIME_LOG_ERROR, "加密密钥错误,密钥长度必须为16");
        return -1;
    }
    // 异或加密逻辑(客户看不到)
    return data ^ (key[0] + key[7] + key[15]);
}

// 简单异或解密
static int decryptData(int data, const char* key) {
    if (key == nullptr || strlen(key) != 16) {
        logOutput(RUNTIME_LOG_ERROR, "解密密钥错误,密钥长度必须为16");
        return -1;
    }
    // 异或解密(和加密逻辑一致,客户看不到)
    return data ^ (key[0] + key[7] + key[15]);
}

// 对外提供的加密接口(内部调用)
int encryptParam(int param, const char* key) {
    std::lock_guard<std::mutex> lock(g_encryptMutex);
    return encryptData(param, key);
}

// 对外提供的解密接口(内部调用)
int decryptParam(int param, const char* key) {
    std::lock_guard<std::mutex> lock(g_encryptMutex);
    return decryptData(param, key);
}
2.3.4 src/ErrorCode.cpp(错误码实现)
cpp 复制代码
#include "Runtime.h"

// 错误码对应错误信息(客户看不到实现,仅能通过接口查询)
const char* Runtime_GetErrorMsg(Runtime_ErrorCode errCode) {
    switch (errCode) {
        case RUNTIME_SUCCESS:    return "操作成功";
        case RUNTIME_ERROR_UNINIT: return "Runtime未初始化,请先调用Runtime_Init";
        case RUNTIME_ERROR_PARAM:  return "参数错误(空指针/非法值)";
        case RUNTIME_ERROR_ENCRYPT: return "加密/解密失败(密钥错误/参数异常)";
        case RUNTIME_ERROR_THREAD: return "多线程调用异常(内部锁错误)";
        case RUNTIME_ERROR_UNKNOWN: return "未知错误,请检查日志";
        default: return "无效错误码";
    }
}

#ifdef __cplusplus
std::string Runtime::getLastErrorMsg() const {
    return Runtime_GetErrorMsg(getLastError());
}
#endif
2.3.5 src/Runtime.cpp(核心业务实现,含多线程安全)
cpp 复制代码
#include "Runtime.h"
#include <mutex>
#include <string>

// 全局初始化状态
static bool g_isInitialized = false;
static std::mutex g_initMutex; // 初始化锁,多线程安全

// C++类实现(PIMPL模式,客户看不到内部成员)
class Runtime::Impl {
public:
    Impl() {
        m_lastError = RUNTIME_SUCCESS;
    }

    Impl(Runtime_LogLevel logLevel, const std::string& logPath) {
        m_lastError = RUNTIME_SUCCESS;
        Runtime_Init(logLevel, logPath.c_str());
    }

    ~Impl() {
        Runtime_Shutdown();
    }

    Runtime_ErrorCode m_lastError;
};

// 初始化接口实现
Runtime_ErrorCode Runtime_Init(Runtime_LogLevel logLevel, const char* logPath) {
    std::lock_guard<std::mutex> lock(g_initMutex);
    if (g_isInitialized) {
        logOutput(RUNTIME_LOG_INFO, "Runtime已初始化,无需重复调用");
        return RUNTIME_SUCCESS;
    }

    // 校验参数
    if (logLevel < RUNTIME_LOG_DEBUG || logLevel > RUNTIME_LOG_ERROR) {
        logOutput(RUNTIME_LOG_ERROR, "初始化失败:日志级别参数错误");
        return RUNTIME_ERROR_PARAM;
    }

    // 配置日志
    setLogConfig(logLevel, logPath);

    // 内部初始化逻辑(客户看不到,如加载配置、初始化资源等)
    logOutput(RUNTIME_LOG_INFO, "Runtime初始化成功(内部机密逻辑执行完成)");
    g_isInitialized = true;
    return RUNTIME_SUCCESS;
}

// 业务计算接口实现(加密+多线程安全)
int Runtime_Calculate(int a, int b, const char* key) {
    std::lock_guard<std::mutex> lock(g_initMutex);
    // 校验初始化状态
    if (!g_isInitialized) {
        logOutput(RUNTIME_LOG_ERROR, "计算失败:Runtime未初始化");
        return -1;
    }

    // 校验参数
    if (key == nullptr || strlen(key) != 16) {
        logOutput(RUNTIME_LOG_ERROR, "计算失败:密钥错误");
        return -1;
    }

    // 解密参数(客户看不到解密过程)
    int decA = decryptParam(a, key);
    int decB = decryptParam(b, key);
    if (decA == -1 || decB == -1) {
        logOutput(RUNTIME_LOG_ERROR, "计算失败:参数解密失败");
        return -1;
    }

    // 核心业务逻辑(客户看不到,可替换为你的实际功能)
    int result = decA * 100 + decB;
    logOutput(RUNTIME_LOG_DEBUG, "计算完成:解密后参数(a=%d, b=%d),结果=%d", decA, decB, result);

    // 加密结果返回
    return encryptParam(result, key);
}

// 反初始化接口实现
void Runtime_Shutdown() {
    std::lock_guard<std::mutex> lock(g_initMutex);
    if (!g_isInitialized) {
        return;
    }

    // 内部反初始化逻辑(客户看不到,如释放资源、保存数据等)
    logOutput(RUNTIME_LOG_INFO, "Runtime反初始化成功(内部资源已释放)");
    g_isInitialized = false;
}

// C++类接口实现
#ifdef __cplusplus
Runtime::Runtime() {
    m_impl = new Impl();
    m_impl->m_lastError = Runtime_Init(RUNTIME_LOG_INFO, nullptr);
}

Runtime::Runtime(Runtime_LogLevel logLevel, const std::string& logPath) {
    m_impl = new Impl(logLevel, logPath);
    m_impl->m_lastError = Runtime_Init(logLevel, logPath.c_str());
}

Runtime::~Runtime() {
    delete m_impl;
    m_impl = nullptr;
}

int Runtime::calculate(int a, int b, const std::string& key) {
    int result = Runtime_Calculate(a, b, key.c_str());
    if (result == -1) {
        m_impl->m_lastError = RUNTIME_ERROR_ENCRYPT;
    } else {
        m_impl->m_lastError = RUNTIME_SUCCESS;
    }
    return result;
}

Runtime_ErrorCode Runtime::getLastError() const {
    return m_impl->m_lastError;
}
#endif

2.4 CMakeLists.txt(编译+自动打包,你自己用)

cmake 复制代码
cmake_minimum_required(VERSION 3.14)
project(RuntimeSDK CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# 1. 生成动态库
add_library(runtime SHARED
    src/Runtime.cpp
    src/Version.cpp
    src/Log.cpp
    src/Encrypt.cpp
    src/ErrorCode.cpp
)

# 2. 公开头文件目录
target_include_directories(runtime
PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# 3. Windows导出符号
target_compile_definitions(runtime
PRIVATE
    RUNTIME_EXPORT
)

# 4. 输出目录配置(统一输出lib/bin,方便打包)
set_target_properties(runtime PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
    # 避免Windows下DLL和EXE同名冲突
    RUNTIME_OUTPUT_NAME "runtime_sdk"
    LIBRARY_OUTPUT_NAME "runtime_sdk"
    ARCHIVE_OUTPUT_NAME "runtime_sdk"
)

# 5. 自动打包脚本(编译完成后自动打包SDK)
include(script/pack_sdk.cmake)

# 6. 多线程安全配置(Windows链接多线程库)
if(WIN32)
    target_link_libraries(runtime PRIVATE ws2_32.lib)
    target_compile_options(runtime PRIVATE /MT) # 静态链接C runtime,避免客户缺少依赖
endif()

2.5 自动打包脚本(script/pack_sdk.cmake)

cmake 复制代码
# 自动打包SDK:头文件+lib+dll+说明文档
set(SDK_PACKAGE_NAME "RuntimeSDK_Client")
set(SDK_PACKAGE_DIR ${CMAKE_BINARY_DIR}/${SDK_PACKAGE_NAME})

# 创建打包目录结构
file(MAKE_DIRECTORY ${SDK_PACKAGE_DIR}/include)
file(MAKE_DIRECTORY ${SDK_PACKAGE_DIR}/lib)
file(MAKE_DIRECTORY ${SDK_PACKAGE_DIR}/bin)
file(MAKE_DIRECTORY ${SDK_PACKAGE_DIR}/doc)

# 复制头文件
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/include/Runtime.h
     DESTINATION ${SDK_PACKAGE_DIR}/include)

# 复制lib文件(Windows)
if(WIN32)
    file(COPY ${CMAKE_BINARY_DIR}/lib/runtime_sdk.lib
         DESTINATION ${SDK_PACKAGE_DIR}/lib)
# 复制so文件(Linux)
else()
    file(COPY ${CMAKE_BINARY_DIR}/lib/libruntime_sdk.so
         DESTINATION ${SDK_PACKAGE_DIR}/lib)
endif()

# 复制dll文件(Windows)
if(WIN32)
    file(COPY ${CMAKE_BINARY_DIR}/bin/runtime_sdk.dll
         DESTINATION ${SDK_PACKAGE_DIR}/bin)
endif()

# 生成说明文档(告诉客户如何使用)
set(SDK_README ${SDK_PACKAGE_DIR}/doc/使用说明.md)
file(WRITE ${SDK_README}
"# Runtime SDK 使用说明
## 一、SDK包含文件
- include/Runtime.h:接口头文件(仅需包含此文件)
- lib/runtime_sdk.lib:链接库(Windows)/libruntime_sdk.so(Linux)
- bin/runtime_sdk.dll:运行时库(Windows,需放在EXE同目录)

## 二、编译配置(CMake示例)
cmake_minimum_required(VERSION 3.14)
project(ClientApp CXX)
set(CMAKE_CXX_STANDARD 17)

add_executable(app main.cpp)
target_include_directories(app PRIVATE ./include)
target_link_directories(app PRIVATE ./lib)
if(WIN32)
    target_link_libraries(app PRIVATE runtime_sdk.lib)
else()
    target_link_libraries(app PRIVATE runtime_sdk)
endif()

## 三、接口调用示例(C++)
#include <iostream>
#include \"Runtime.h\"

int main() {
    // 方式1:C接口调用
    Runtime_Init(RUNTIME_LOG_INFO, nullptr);
    std::cout << \"版本:\" << Runtime_GetVersion() << std::endl;
    
    // 加密参数(密钥长度16)
    const char* key = \"RuntimeSDK202604\";
    int a = encryptParam(10, key); // 客户可自行加密参数
    int b = encryptParam(20, key);
    int result = Runtime_Calculate(a, b, key);
    result = decryptParam(result, key); // 解密结果
    std::cout << \"计算结果:\" << result << std::endl;
    
    Runtime_Shutdown();

    // 方式2:C++类接口调用
    Runtime runtime(RUNTIME_LOG_INFO, \"client_log.log\");
    std::cout << \"版本:\" << runtime.getVersion() << std::endl;
    int a2 = encryptParam(30, key);
    int b2 = encryptParam(40, key);
    int result2 = runtime.calculate(a2, b2, key);
    result2 = decryptParam(result2, key);
    std::cout << \"计算结果:\" << result2 << std::endl;

    return 0;
}

## 四、错误排查
1. 调用接口返回错误码,可通过Runtime_GetErrorMsg(errCode)获取错误信息
2. 日志文件默认生成在当前目录,可通过初始化接口自定义日志路径
3. 确保密钥长度为16位,否则加密/解密会失败
4. 多线程调用无需额外处理,内部已保证线程安全

## 五、注意事项
- 禁止反编译、修改SDK文件
- 仅可用于授权范围内的开发使用
- 运行时需确保dll/so文件与EXE同目录(Windows)
")

# 打包完成提示
message(STATUS "SDK打包完成,路径:${SDK_PACKAGE_DIR}")
message(STATUS "打包内容:头文件、lib、dll、使用说明")

3、客户调用工程

3.1 客户拿到的文件(打包后自动生成)

plain 复制代码
RuntimeSDK_Client/
├── include/
│   └── Runtime.h          # 仅接口,无实现
├── lib/
│   └── runtime_sdk.lib    # Windows链接库(无源码)
├── bin/
│   └── runtime_sdk.dll    # Windows运行时库(二进制)
└── doc/
    └── 使用说明.md        # 调用说明,客户可参考

3.2 客户的CMakeLists.txt(仅链接二进制)

cmake 复制代码
cmake_minimum_required(VERSION 3.14)
project(ClientApp CXX)

set(CMAKE_CXX_STANDARD 17)

# 生成客户的可执行程序
add_executable(app main.cpp)

# 包含SDK头文件(仅接口)
target_include_directories(app PRIVATE ./include)

# 链接SDK的二进制lib(无源码)
target_link_directories(app PRIVATE ./lib)

# 区分Windows/Linux链接
if(WIN32)
    target_link_libraries(app PRIVATE runtime_sdk.lib)
    # 确保DLL和EXE同目录
    add_custom_command(TARGET app POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
        ${CMAKE_CURRENT_SOURCE_DIR}/bin/runtime_sdk.dll
        $<TARGET_FILE_DIR:app>)
else()
    target_link_libraries(app PRIVATE runtime_sdk)
endif()

3.3 客户的调用代码(main.cpp,仅用接口)

cpp 复制代码
#include <iostream>
#include "Runtime.h"
#include <string>

// 辅助函数:加密/解密(客户可调用,接口可见,实现不可见)
int encrypt(int data, const std::string& key) {
    return encryptParam(data, key.c_str());
}

int decrypt(int data, const std::string& key) {
    return decryptParam(data, key.c_str());
}

int main() {
    // --------------- 方式1:C接口调用 ---------------
    std::cout << "=== C接口调用 ===" << std::endl;
    // 初始化(日志级别INFO,默认日志路径)
    Runtime_ErrorCode err = Runtime_Init(RUNTIME_LOG_INFO, nullptr);
    if (err != RUNTIME_SUCCESS) {
        std::cout << "初始化失败:" << Runtime_GetErrorMsg(err) << std::endl;
        return 1;
    }

    // 获取版本号
    std::cout << "SDK版本:" << Runtime_GetVersion() << std::endl;

    // 业务计算(参数加密)
    const std::string key = "RuntimeSDK202604"; // 密钥(长度16)
    int a = 15, b = 35;
    int encryptA = encrypt(a, key);
    int encryptB = encrypt(b, key);
    std::cout << "加密前:a=" << a << ", b=" << b << std::endl;
    std::cout << "加密后:a=" << encryptA << ", b=" << encryptB << std::endl;

    int encryptResult = Runtime_Calculate(encryptA, encryptB, key.c_str());
    if (encryptResult == -1) {
        std::cout << "计算失败:" << Runtime_GetErrorMsg(Runtime_ERROR_ENCRYPT) << std::endl;
        Runtime_Shutdown();
        return 1;
    }

    int result = decrypt(encryptResult, key);
    std::cout << "计算结果(解密后):" << result << std::endl;

    // 反初始化
    Runtime_Shutdown();

    // --------------- 方式2:C++类接口调用 ---------------
    std::cout << "\n=== C++类接口调用 ===" << std::endl;
    // 初始化(自定义日志路径)
    Runtime runtime(RUNTIME_LOG_DEBUG, "client_runtime.log");
    if (runtime.getLastError() != RUNTIME_SUCCESS) {
        std::cout << "初始化失败:" << runtime.getLastErrorMsg() << std::endl;
        return 1;
    }

    // 获取版本号
    std::cout << "SDK版本:" << runtime.getVersion() << std::endl;

    // 业务计算
    int a2 = 25, b2 = 45;
    int encryptA2 = encrypt(a2, key);
    int encryptB2 = encrypt(b2, key);
    std::cout << "加密前:a=" << a2 << ", b=" << b2 << std::endl;
    std::cout << "加密后:a=" << encryptA2 << ", b=" << encryptB2 << std::endl;

    int encryptResult2 = runtime.calculate(encryptA2, encryptB2, key);
    if (encryptResult2 == -1) {
        std::cout << "计算失败:" << runtime.getLastErrorMsg() << std::endl;
        return 1;
    }

    int result2 = decrypt(encryptResult2, key);
    std::cout << "计算结果(解密后):" << result2 << std::endl;

    std::cout << "\n调用完成!" << std::endl;
    return 0;
}

4、核心保障

  1. 客户仅拿到头文件(接口)、二进制lib/dll,无任何.cpp源码,无法查看内部实现;

  2. C++类采用PIMPL模式,私有成员和实现完全隐藏,客户看不到类的内部状态;

  3. 加密、日志、错误码的核心逻辑都在src目录,不泄露给客户;

  4. 自动打包脚本仅复制公开文件,内部实现文件不会被打包;

  5. 多线程安全通过内部锁实现,客户无需关心,也看不到锁的实现细节。

5、使用步骤

5.1 SDK编译+打包

  1. 创建上述RuntimeSDK工程,将src、include、script目录及CMakeLists.txt复制到位;

  2. 用CMake构建工程(如VS、Clion、CMake-GUI),编译后自动生成lib/bin目录;

  3. 编译完成后,CMake自动调用打包脚本,生成RuntimeSDK_Client目录;

  4. 将RuntimeSDK_Client目录发给客户,自己保留RuntimeSDK工程(不泄露)。

5.2 客户调用SDK

  1. 解压你发给的RuntimeSDK_Client压缩包;

  2. 创建自己的ClientApp工程,复制客户的CMakeLists.txt和main.cpp;

  3. 用CMake构建工程,编译生成app.exe;

  4. 运行app.exe,即可调用SDK接口,看不到任何实现。

6、可扩展说明

  1. 加密算法:当前为简化版异或加密,可替换为AES、RSA等成熟算法(修改src/Encrypt.cpp即可,不影响客户接口);

  2. 业务逻辑:可修改src/Runtime.cpp中的Runtime_Calculate函数,替换为你的核心业务功能,客户无需修改调用代码;

  3. 日志功能:可扩展日志轮转、日志过滤等功能(修改src/Log.cpp);

  4. 错误码:可新增更多错误码(修改Runtime.h和src/ErrorCode.cpp),客户可通过接口查询新增错误信息。

五、runtime SDK库引用方式

1、把 SDK 放在电脑上一个固定的公共位置,所有工程都去这里引用,不复制文件

给客户的 SDK 放在一个固定公共目录

比如客户在自己电脑上创建:

复制代码
C:\MyCompanySDK\RuntimeSDK\
├─ include\      # 头文件
├─ lib\          # lib
└─ bin\          # dll

只放这一份!所有项目都共用它!


客户 CMake

直接用 绝对路径 指向公共SDK目录:

cmake 复制代码
# 客户只需要改这里的 SDK 安装路径
set(SDK_PATH "C:/MyCompanySDK/RuntimeSDK")

# 头文件:从公共SDK里取,不复制
target_include_directories(app PRIVATE ${SDK_PATH}/include)

# 库目录:指向公共 lib
target_link_directories(app PRIVATE ${SDK_PATH}/lib)

# 链接公共库
target_link_libraries(app PRIVATE runtime_sdk.lib)

2、"引用"一个公共位置的库

给客户的支持包

  1. include/
  2. lib/
  3. bin/

客户解压到 任意一个固定目录 (比如 D:/MySDK/
所有工程都共用这一份,永不复制!


客户cmak

cmake 复制代码
# 只需要配置 SDK 路径 1 次
set(SDK_PATH "D:/MySDK")

# 自动链接 头文件 + lib + dll
include(${SDK_PATH}/sdk_config.cmake)
target_link_sdk(app)

给客户的 SDK 根目录里,加一个文件sdk_config.cmake

cmake 复制代码
# ============ SDK 自动配置脚本 ============
# 作用:自动配置 头文件 + lib + dll
# 客户:只需要调用 target_link_sdk(你的目标名)

if(NOT SDK_PATH)
    message(FATAL_ERROR "请先设置 SDK_PATH 路径!例:set(SDK_PATH \"D:/MySDK\")")
endif()

# 自动找到头文件
set(SDK_INCLUDE ${SDK_PATH}/include)

# 自动找到 lib 目录
set(SDK_LIB_DIR ${SDK_PATH}/lib)

# 自动找到 dll 目录
set(SDK_BIN_DIR ${SDK_PATH}/bin)

# 库文件名
set(SDK_LIB_NAME runtime_sdk.lib)

# 宏:客户只需要调用这个函数
macro(target_link_sdk target_name)

    # 自动加头文件路径
    target_include_directories(${target_name} PRIVATE ${SDK_INCLUDE})

    # 自动加库路径
    target_link_directories(${target_name} PRIVATE ${SDK_LIB_DIR})

    # 自动链接 lib
    target_link_libraries(${target_name} PRIVATE ${SDK_LIB_NAME})

    # Windows 自动复制 dll 到 exe 目录(客户完全不用管)
    if(WIN32)
        add_custom_command(TARGET ${target_name} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy
            ${SDK_BIN_DIR}/runtime_sdk.dll
            $<TARGET_FILE_DIR:${target_name}>
        )
    endif()

    message(STATUS "✅ SDK 链接成功:${SDK_PATH}")
endmacro()

给客户的 SDK 最终目录结构

复制代码
D:/MySDK/
├─ include/           # 你的头文件
├─ lib/               # 你的 lib
├─ bin/               # 你的 dll
└─ sdk_config.cmake   # 我上面给你的文件

客户 CMakeLists.txt

cmake 复制代码
cmake_minimum_required(VERSION 3.14)
project(ClientDemo)

set(CMAKE_CXX_STANDARD 17)

# 1. 指定 SDK 路径(只写一次)
set(SDK_PATH "D:/MySDK")

# 2. 导入 SDK 配置
include(${SDK_PATH}/sdk_config.cmake)

# 3. 生成可执行程序
add_executable(app main.cpp)

# 4. 一键链接 SDK
target_link_sdk(app)

客户 main.cpp

cpp 复制代码
#include "Runtime.h"

int main() {
    Runtime_Init(...);
    ...
}

3、添加环境变量

发给客户的 SDK 结构

复制代码
YourSDK/
├── cmake/
│   └── FindRuntimeSDK.cmake    # 自动查找SDK(核心)
├── include/
│   └── Runtime.h               # 接口头文件
├── lib/
│   └── runtime_sdk.lib         # 链接库
├── bin/
│   └── runtime_sdk.dll         # 运行库
├── RuntimeSDKConfig.cmake      # 自动配置
└── RuntimeSDKConfigVersion.cmake

客户 CMakeLists.txt

cmake 复制代码
find_package(RuntimeSDK REQUIRED)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE RuntimeSDK::RuntimeSDK)

cmake/FindRuntimeSDK.cmake

cmake 复制代码
# 自动寻找 RuntimeSDK
set(RuntimeSDK_FOUND TRUE)

get_filename_component(SDK_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)

set(RuntimeSDK_INCLUDE_DIRS "${SDK_DIR}/include")
set(RuntimeSDK_LIBRARY_DIRS "${SDK_DIR}/lib")
set(RuntimeSDK_BIN_DIRS "${SDK_DIR}/bin")
set(RuntimeSDK_LIBRARIES runtime_sdk.lib)

add_library(RuntimeSDK::RuntimeSDK UNKNOWN IMPORTED)

set_target_properties(RuntimeSDK::RuntimeSDK PROPERTIES
    IMPORTED_LOCATION "${SDK_DIR}/lib/runtime_sdk.lib"
    INTERFACE_INCLUDE_DIRECTORIES "${SDK_DIR}/include"
)

if(WIN32)
    set_target_properties(RuntimeSDK::RuntimeSDK PROPERTIES
        IMPORTED_IMPLIB "${SDK_DIR}/lib/runtime_sdk.lib"
    )
endif()

message(STATUS "✅ RuntimeSDK 自动加载成功: ${SDK_DIR}")

RuntimeSDKConfig.cmake

cmake 复制代码
include(${CMAKE_CURRENT_LIST_DIR}/cmake/FindRuntimeSDK.cmake)

RuntimeSDKConfigVersion.cmake

cmake 复制代码
set(PACKAGE_VERSION "1.0.0")
set(PACKAGE_VERSION_MAJOR 1)
set(PACKAGE_VERSION_MINOR 0)
set(PACKAGE_VERSION_PATCH 0)

if(PACKAGE_VERSION_MAJOR VERSION_EQUAL PACKAGE_FIND_VERSION_MAJOR)
    set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
    set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()

if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION)
    set(PACKAGE_VERSION_EXACT TRUE)
endif()

把 SDK 根目录添加到系统环境变量

变量名:CMAKE_PREFIX_PATH

变量值:D:\YourSDK(SDK 所在目录)

客户 CMakeLists.txt

cmake 复制代码
cmake_minimum_required(VERSION 3.14)
project(ClientDemo)

set(CMAKE_CXX_STANDARD 17)

# 1. 自动寻找SDK(不用路径!不用配置!)
find_package(RuntimeSDK REQUIRED)

# 2. 生成程序
add_executable(app main.cpp)

# 3. 链接SDK(自动包含头文件+lib+复制dll)
target_link_libraries(app PRIVATE RuntimeSDK::RuntimeSDK)

客户 main.cpp

cpp 复制代码
#include "Runtime.h"

int main() {
    Runtime_Init(RUNTIME_LOG_INFO, nullptr);
    Runtime_GetVersion();
    Runtime_Shutdown();
    return 0;
}

优势

多工程共用同一个SDK,不复制任何文件

客户不用写任何路径

客户不用管头文件在哪、lib在哪、dll在哪

更新SDK只需覆盖文件夹,所有工程自动更新

项目目录干净,不包含任何SDK文件

CMake 自动查找、自动配置、自动链接

Windows/Linux 跨平台通用

商业产品级标准方案

你一次部署,终身不用改


六、使用说明

1、SDK 目录结构(无需改动)

复制代码
RuntimeSDK/
├─ bin/runtime_sdk.dll    # 运行必需
├─ lib/runtime_sdk.lib    # 链接用
├─ include/Runtime.h      # 接口头文件
├─ cmake/FindRuntimeSDK.cmake
├─ RuntimeSDKConfig.cmake
├─ RuntimeSDKConfigVersion.cmake
└─ 使用说明.txt

2、添加系统环境变量

1. 打开:系统属性 → 高级 → 环境变量

2. 在「系统变量」里点击「新建」

  • 变量名: RUNTIME_SDK_ROOT
  • 变量值: 你解压的 SDK 路径,例如
    D:\RuntimeSDKC:\SDK\RuntimeSDK

3. 确定保存

配置一次,所有工程永久生效,以后不用再配。


3、 CMake 文件

cmake 复制代码
cmake_minimum_required(VERSION 3.14)
project(ClientDemo)

set(CMAKE_CXX_STANDARD 17)

# 自动查找 SDK(无需路径、无需复制文件)
find_package(RuntimeSDK REQUIRED)

# 你的可执行文件
add_executable(app main.cpp)

# 自动链接:头文件 + lib + 自动拷贝 dll
target_link_libraries(app PRIVATE RuntimeSDK::RuntimeSDK)

4、代码示例(main.cpp)

cpp 复制代码
#include <iostream>
#include "Runtime.h"

int main()
{
    // 初始化
    Runtime_ErrorCode ret = Runtime_Init(RUNTIME_LOG_INFO, nullptr);
    if (ret != RUNTIME_SUCCESS)
    {
        std::cout << "初始化失败:" << Runtime_GetErrorMsg(ret) << std::endl;
        return 1;
    }

    // 打印版本
    std::cout << "版本:" << Runtime_GetVersion() << std::endl;

    // 反初始化
    Runtime_Shutdown();

    return 0;
}

5、常见问题

1. 提示"找不到 Runtime.h"

  • 检查环境变量 RUNTIME_SDK_ROOT 路径是否正确
  • 重启 CMake / VS 再试

2. 提示"无法找到 runtime_sdk.lib"

  • 检查路径是否指向 SDK根目录
  • 不要指向 libbin

3. 运行提示"缺少 runtime_sdk.dll"

  • CMake 会自动拷贝 dll 到 exe 目录
  • 重新生成一次工程即可

4. 多个项目共用?

  • 完全可以,所有项目共用这一个 SDK
  • 更新只需替换这一份 SDK,所有项目自动生效

七、批处理

1. 批处理:一键设置 SDK 环境变量

文件名:设置SDK环境变量.bat

batch 复制代码
@echo off
chcp 65001 >nul
echo ==============================================
echo          RuntimeSDK 环境变量自动设置
echo ==============================================
echo.

:: 获取当前 bat 所在目录(即 SDK 根目录)
set "SDK_PATH=%~dp0"
:: 去掉最后的反斜杠
set "SDK_PATH=%SDK_PATH:~0,-1%"

echo 检测到 SDK 路径:%SDK_PATH%
echo.
echo 即将设置系统环境变量:RUNTIME_SDK_ROOT
echo 变量值:%SDK_PATH%
echo.
pause

:: 设置用户级环境变量(不需要管理员,更安全)
setx RUNTIME_SDK_ROOT "%SDK_PATH%"

echo.
echo ==============================================
echo          ✅ 环境变量设置完成!
echo   请重启 CMake / VS / 编辑器后生效
echo ==============================================
echo.
pause

使用方法:

把这个 .bat 放在 RuntimeSDK 根目录 ,客户双击运行 ,自动识别路径并设置环境变量,不用手动打字


2. 批处理:一键清除 SDK 环境变量

文件名:清除SDK环境变量.bat

batch 复制代码
@echo off
chcp 65001 >nul
echo ==============================================
echo          清除 RuntimeSDK 环境变量
echo ==============================================
echo.

setx RUNTIME_SDK_ROOT ""
echo.
echo ✅ 已清除环境变量 RUNTIME_SDK_ROOT
echo.
pause

3. 卸载 / 清理说明.txt

复制代码
RuntimeSDK 卸载与清理说明

一、完全卸载
1. 删除整个 RuntimeSDK 文件夹
2. 运行"清除SDK环境变量.bat"
3. 清理完成

二、更新 SDK
1. 直接用新版文件夹覆盖旧版
2. 无需重新设置环境变量
3. 客户工程重新 CMake 生成即可

三、手动清理环境变量(可选)
如果不想用批处理,可以手动删除:
变量名:RUNTIME_SDK_ROOT

四、客户项目是否需要清理?
不需要。
SDK 与项目完全分离,不污染项目代码,删除 SDK 不影响客户工程。

4. 客户完整目录

复制代码
RuntimeSDK/
├─ bin/
│  └─ runtime_sdk.dll
├─ lib/
│  └─ runtime_sdk.lib
├─ include/
│  └─ Runtime.h
├─ cmake/
│  └─ FindRuntimeSDK.cmake
├─ RuntimeSDKConfig.cmake
├─ RuntimeSDKConfigVersion.cmake
├─ 设置SDK环境变量.bat       ← 新增
├─ 清除SDK环境变量.bat       ← 新增
├─ 使用说明.txt              ← 之前的
└─ 卸载与清理说明.txt        ← 新增
相关推荐
旖-旎2 小时前
分治(快速选择算法)(3)
c++·算法·leetcode·排序算法·快速选择
xiaoye-duck2 小时前
【C++:哈希表封装】哈希表封装 myunordered_map/myunordered_set 实战:底层原理 + 完整实现
数据结构·c++·散列表
A.A呐3 小时前
【C++第二十三章】C++11
开发语言·c++
亿秒签到3 小时前
L2-007 家庭房产
数据结构·c++·算法
2401_892070984 小时前
【Linux C++ 日志系统实战】日志消息对象 LogMessage 完整实现:流式拼装 + 标准化输出
linux·c++·日志系统·流式日志
paeamecium4 小时前
【PAT甲级真题】- Longest Symmetric String (25)
数据结构·c++·算法·pat考试
A.A呐5 小时前
【C++第二十二章】哈希与散列
c++·算法·哈希算法
wangjialelele5 小时前
从磁盘查找理解 B 树 | B+树:原理、插入、分裂与性能分析
c语言·开发语言·数据结构·c++·b树
Tanecious.5 小时前
蓝桥杯备赛:Day1-P1101 单词方阵
c语言·c++·蓝桥杯
木子墨5166 小时前
LeetCode 热题 100 精讲 | 链表篇:反转链表·环形链表·有序链表·LRU
数据结构·c++·算法·力扣