Skip to content

功能请求:入口由依赖提供(kind = "app" 支持用 entry = "<依赖>" 代替 main) #845

Open

Description

@Sunrisepeak

背景

有一类常见的需求:程序的入口由框架提供,应用只写回调,或者干脆只有资源和脚本。

  • gtest_main:测试程序不写 main,由 gtest 提供。
  • SDL3 main callbacks(SDL_MAIN_USE_CALLBACKS):应用实现 SDL_AppInit、SDL_AppIterate、SDL_AppEvent、SDL_AppQuit,main 由 SDL 提供。
  • Qt:在 Windows 上提供 qtmain / WinMain。
  • openmui(一个基于 mcpp 的 UI 框架,正在设计中):纯 TS / Python / Lua 应用没有任何 C++ 源文件,入口是框架的“播放器”,它读取清单,再加载视图和脚本;C++ 应用也可以选择只实现 omui_app() 回调,由框架提供 main。

另外,kind = "app" 在 *-linux-android 上本来就是“由平台约定入口”的共享库,所以“入口不一定由当前包写出”这件事在 mcpp 里已经有先例了。

现状

kind = "app"(2026.9.12.3 起)和 kind = "bin" 一样,要求 main = "<本包内的文件>"(docs/04-mcpp-toml.md,kind = "app" 一节)。所以框架只能让模板生成一个用户自己维护的 src/main.cpp:

import openmui.player;
int main(int c, char** v) { return omui::player::run(c, v); }

这个办法能用,但有几个问题:

  • 每个应用都要带一个样板文件;
  • 框架升级时如果入口的签名变了,就要改每个应用;
  • 对纯脚本应用来说,“工程里必须有一个 .cpp 文件”很难理解。

提议:入口可以由依赖的某个特性提供

使用方:

[dependencies]
openmui = { version = "0.1", features = ["entry-player"] }

[targets.notes]
kind  = "app"
entry = "openmui"     # 入口由依赖 openmui 的某个已启用特性提供;和 main 互斥

提供方(框架包):

[features.entry-player]
entry = "src/entry/player.cpp"    # 声明:这个特性提供入口翻译单元

[features.entry-app]
entry = "src/entry/app.cpp"       # 另一种入口:调用应用实现的回调

建议的语义:

  1. 一个目标里 main 和 entry 只能写一个。
  2. entry = "<依赖>" 指向的依赖必须恰好有一个已启用的特性声明了 entry。没有或者有多个时报错,并列出候选的特性。
  3. 入口翻译单元作为使用方目标的入口来编译和链接:它可以 import 提供方的模块,也可以引用使用方定义的符号(例如框架声明、应用实现的 extern "C++" omui::AppSpec omui_app();)。
  4. 在所有平台上的效果和现在写 main 完全一样:bin / app 的可执行文件形式、Android 上的共享库形式、windows_subsystem / windows_entry、mcpp run、mcpp pack、mcpp test。
  5. 诊断信息要写明入口来自哪个依赖的哪个特性,方便排查。

不改变的部分

  • 现有写 main 的工程完全不受影响。
  • 模板机制不变:模板仍然可以选择生成一个可见的 main.cpp(作为过渡)。

备选方案(不太理想)

  • 由规则包生成入口源文件(role = "source"):但 main 字段需要的是一个写死的路径,而且入口不应该依赖构建插件。
  • 由库导出 main 符号(gtest_main 那种做法):可移植性差(Android 和 Windows 的入口形式不同),mcpp 也无法给出清楚的诊断。

如果方向可以,openmui 这边可以先用模板生成 main.cpp 的办法过渡,等这个能力落地后再切换过去。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions