diff options
| -rw-r--r-- | .github/workflows/linux.yml | 9 | ||||
| -rw-r--r-- | CHANGELOG.md | 212 | ||||
| -rw-r--r-- | core/src/cli/xmake.lua | 6 | ||||
| -rwxr-xr-x | core/src/cli/xmake.sh | 3 | ||||
| m--------- | core/src/tbox/tbox | 0 | ||||
| -rw-r--r-- | core/src/xmake/binutils/ar/extractlib.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/binutils/extractlib.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/engine.c | 6 | ||||
| -rw-r--r-- | core/src/xmake/engine_pool.c | 21 | ||||
| -rw-r--r-- | core/src/xmake/io/file_close.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/io/file_write.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/os/cpuinfo.c | 4 | ||||
| -rw-r--r-- | core/src/xmake/os/meminfo.c | 5 | ||||
| -rw-r--r-- | core/src/xmake/process/open.c | 14 | ||||
| -rw-r--r-- | core/src/xmake/semver/select.c | 120 | ||||
| -rw-r--r-- | core/src/xmake/utf8/width.c | 6 | ||||
| -rw-r--r-- | core/xmake.lua | 2 | ||||
| -rwxr-xr-x | core/xmake.sh | 2 | ||||
| -rwxr-xr-x | scripts/get.ps1 | 2 | ||||
| -rw-r--r-- | scripts/rpmbuild/xmake.spec | 2 | ||||
| -rw-r--r-- | tests/actions/addon/custom-include/addon.lua | 2 | ||||
| -rw-r--r-- | tests/actions/addon/custom-include/includes/check/xmake.lua | 4 | ||||
| -rw-r--r-- | tests/actions/addon/custom-module/addon.lua | 2 | ||||
| -rw-r--r-- | tests/actions/addon/custom-module/modules/greeting.lua | 3 | ||||
| -rw-r--r-- | tests/actions/addon/custom-override/addon.lua | 2 | ||||
| -rw-r--r-- | tests/actions/addon/custom-override/plugins/format/main.lua | 3 | ||||
| -rw-r--r-- | tests/actions/addon/custom-override/plugins/format/xmake.lua | 6 | ||||
| -rw-r--r-- | tests/actions/addon/custom-package/addon.lua | 2 | ||||
| -rw-r--r-- | tests/actions/addon/custom-package/includes/packages/src/include/hello_utils.h | 6 | ||||
| -rw-r--r-- | tests/actions/addon/custom-package/includes/packages/xmake.lua | 13 | ||||
| -rw-r--r-- | tests/actions/addon/custom-plugin/addon.lua | 2 | ||||
| -rw-r--r-- | tests/actions/addon/custom-plugin/plugins/hello_addon/main.lua | 5 | ||||
| -rw-r--r-- | tests/actions/addon/custom-plugin/plugins/hello_addon/xmake.lua | 5 | ||||
| -rw-r--r-- | tests/actions/addon/custom-rule/addon.lua | 2 | ||||
| -rw-r--r-- | tests/actions/addon/custom-rule/modules/greeting.lua | 3 | ||||
| -rw-r--r-- | tests/actions/addon/custom-rule/rules/hello/xmake.lua | 6 | ||||
| -rw-r--r-- | tests/actions/addon/custom-template/addon.lua | 2 | ||||
| -rw-r--r-- | tests/actions/addon/custom-template/templates/c/customaddon/hello/src/main.c | 6 | ||||
| -rw-r--r-- | tests/actions/addon/custom-template/templates/c/customaddon/hello/xmake.lua | 5 | ||||
| -rw-r--r-- | tests/actions/addon/custom-toolchain/addon.lua | 6 | ||||
| -rw-r--r-- | tests/actions/addon/custom-toolchain/src/modules/core/tools/mycl6x.lua | 12 | ||||
| -rw-r--r-- | tests/actions/addon/custom-toolchain/src/modules/detect/tools/find_mycl6x.lua | 15 | ||||
| -rw-r--r-- | tests/actions/addon/custom-toolchain/src/toolchains/my-c6000/xmake.lua | 19 | ||||
| -rw-r--r-- | tests/actions/addon/projects/autofetch-badname/xmake.lua | 5 | ||||
| -rw-r--r-- | tests/actions/addon/projects/autofetch-build/src/main.c | 14 | ||||
| -rw-r--r-- | tests/actions/addon/projects/autofetch-build/xmake.lua | 14 | ||||
| -rw-r--r-- | tests/actions/addon/projects/autofetch-lockmiss/xmake-addons.lock | 9 | ||||
| -rw-r--r-- | tests/actions/addon/projects/autofetch-lockmiss/xmake.lua | 4 | ||||
| -rw-r--r-- | tests/actions/addon/projects/autofetch/xmake.lua | 8 | ||||
| -rw-r--r-- | tests/actions/addon/projects/custom-package/src/main.c | 6 | ||||
| -rw-r--r-- | tests/actions/addon/projects/custom-package/xmake.lua | 9 | ||||
| -rw-r--r-- | tests/actions/addon/test.lua | 507 | ||||
| -rw-r--r-- | tests/modules/project_depend/test.lua | 19 | ||||
| -rwxr-xr-x | tests/modules/semver/test.lua | 92 | ||||
| -rw-r--r-- | tests/projects/c++/modules/stdmodules_deps_ordering/src/foo.cpp | 5 | ||||
| -rw-r--r-- | tests/projects/c++/modules/stdmodules_deps_ordering/src/foo.mpp | 3 | ||||
| -rw-r--r-- | tests/projects/c++/modules/stdmodules_deps_ordering/src/main.cpp | 8 | ||||
| -rw-r--r-- | tests/projects/c++/modules/stdmodules_deps_ordering/test.lua | 1 | ||||
| -rw-r--r-- | tests/projects/c++/modules/stdmodules_deps_ordering/xmake.lua | 19 | ||||
| -rw-r--r-- | tests/projects/embed/esp32/blink/boards/esp32c3/board.h | 7 | ||||
| -rw-r--r-- | tests/projects/embed/esp32/blink/src/main.c | 26 | ||||
| -rw-r--r-- | tests/projects/embed/esp32/blink/xmake-addons.lua | 2 | ||||
| -rw-r--r-- | tests/projects/embed/esp32/blink/xmake.lua | 15 | ||||
| -rw-r--r-- | tests/projects/other/bin2c/src/asset.bin | 1 | ||||
| -rw-r--r-- | tests/projects/other/bin2c/src/asset2.bin | 1 | ||||
| -rw-r--r-- | tests/projects/other/bin2c/src/main.c | 29 | ||||
| -rw-r--r-- | tests/projects/other/bin2c/test.lua | 2 | ||||
| -rw-r--r-- | tests/projects/other/bin2c/transform.lua | 5 | ||||
| -rw-r--r-- | tests/projects/other/bin2c/xmake.lua | 10 | ||||
| -rw-r--r-- | tests/projects/other/bin2obj/src/asset.bin | 1 | ||||
| -rw-r--r-- | tests/projects/other/bin2obj/src/asset2.bin | 1 | ||||
| -rw-r--r-- | tests/projects/other/bin2obj/src/main.c | 50 | ||||
| -rw-r--r-- | tests/projects/other/bin2obj/test.lua | 2 | ||||
| -rw-r--r-- | tests/projects/other/bin2obj/transform.lua | 5 | ||||
| -rw-r--r-- | tests/projects/other/bin2obj/xmake.lua | 8 | ||||
| -rw-r--r-- | xmake/actions/addon/main.lua | 334 | ||||
| -rw-r--r-- | xmake/actions/addon/xmake.lua | 49 | ||||
| -rw-r--r-- | xmake/actions/create/main.lua | 40 | ||||
| -rw-r--r-- | xmake/actions/create/template.lua | 80 | ||||
| -rw-r--r-- | xmake/actions/require/xmake.lua | 3 | ||||
| -rw-r--r-- | xmake/core/base/interpreter.lua | 63 | ||||
| -rw-r--r-- | xmake/core/base/os.lua | 17 | ||||
| -rw-r--r-- | xmake/core/base/poller.lua | 16 | ||||
| -rw-r--r-- | xmake/core/base/scheduler.lua | 14 | ||||
| -rw-r--r-- | xmake/core/base/semver.lua | 10 | ||||
| -rw-r--r-- | xmake/core/base/task.lua | 69 | ||||
| -rw-r--r-- | xmake/core/base/thread.lua | 2 | ||||
| -rw-r--r-- | xmake/core/language/language.lua | 2 | ||||
| -rw-r--r-- | xmake/core/package/addon.lua | 826 | ||||
| -rw-r--r-- | xmake/core/package/component.lua | 2 | ||||
| -rw-r--r-- | xmake/core/package/package.lua | 219 | ||||
| -rw-r--r-- | xmake/core/platform/menu.lua | 2 | ||||
| -rw-r--r-- | xmake/core/platform/platform.lua | 2 | ||||
| -rw-r--r-- | xmake/core/project/addons.lua | 140 | ||||
| -rw-r--r-- | xmake/core/project/option.lua | 10 | ||||
| -rw-r--r-- | xmake/core/project/policy.lua | 6 | ||||
| -rw-r--r-- | xmake/core/project/project.lua | 177 | ||||
| -rw-r--r-- | xmake/core/project/rule.lua | 229 | ||||
| -rw-r--r-- | xmake/core/project/target.lua | 14 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/base/scheduler.lua | 6 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/base/semver.lua | 9 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/package/addon.lua | 96 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/project/addons.lua | 35 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/project/project.lua | 4 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/sandbox/module.lua | 62 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua | 13 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/tool/compiler.lua | 4 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/detect/find_directory.lua | 2 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/detect/find_file.lua | 2 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/detect/find_path.lua | 2 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/detect/find_program.lua | 4 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/detect/find_programver.lua | 4 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/error.lua | 36 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/getmetatable.lua | 32 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/next.lua | 36 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/pcall.lua | 36 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/rawequal.lua | 33 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/rawget.lua | 34 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/rawset.lua | 33 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/select.lua | 36 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/lua/setmetatable.lua | 36 | ||||
| -rw-r--r-- | xmake/core/sandbox/sandbox.lua | 95 | ||||
| -rw-r--r-- | xmake/core/tool/compiler.lua | 4 | ||||
| -rw-r--r-- | xmake/core/tool/linker.lua | 2 | ||||
| -rw-r--r-- | xmake/core/tool/tool.lua | 6 | ||||
| -rw-r--r-- | xmake/core/tool/toolchain.lua | 64 | ||||
| -rw-r--r-- | xmake/languages/c++/xmake.lua | 12 | ||||
| -rw-r--r-- | xmake/languages/c/load.lua | 1 | ||||
| -rw-r--r-- | xmake/modules/core/project/depend.lua | 3 | ||||
| -rw-r--r-- | xmake/modules/core/tools/clang.lua | 45 | ||||
| -rw-r--r-- | xmake/modules/core/tools/ml.lua | 20 | ||||
| -rw-r--r-- | xmake/modules/detect/sdks/find_mingw.lua | 3 | ||||
| -rw-r--r-- | xmake/modules/detect/sdks/find_ndk.lua | 2 | ||||
| -rw-r--r-- | xmake/modules/detect/tools/find_emar.lua | 21 | ||||
| -rw-r--r-- | xmake/modules/detect/tools/find_emcc.lua | 19 | ||||
| -rw-r--r-- | xmake/modules/detect/tools/find_emrun.lua | 21 | ||||
| -rw-r--r-- | xmake/modules/detect/tools/find_emxx.lua | 19 | ||||
| -rw-r--r-- | xmake/modules/net/http/download.lua | 73 | ||||
| -rw-r--r-- | xmake/modules/package/manager/install_package.lua | 2 | ||||
| -rw-r--r-- | xmake/modules/package/manager/pkg/install_package.lua | 62 | ||||
| -rw-r--r-- | xmake/modules/package/manager/vcpkg/find_package.lua | 36 | ||||
| -rw-r--r-- | xmake/modules/package/manager/vcpkg/install_package.lua | 5 | ||||
| -rw-r--r-- | xmake/modules/package/manager/vcpkg/utils.lua | 18 | ||||
| -rw-r--r-- | xmake/modules/package/manager/xmake/search_package.lua | 4 | ||||
| -rw-r--r-- | xmake/modules/package/tools/cmake.lua | 34 | ||||
| -rw-r--r-- | xmake/modules/package/tools/xmake.lua | 23 | ||||
| -rw-r--r-- | xmake/modules/private/action/addon/impl/install_addons.lua | 142 | ||||
| -rw-r--r-- | xmake/modules/private/action/addon/impl/xrepo.lua | 57 | ||||
| -rw-r--r-- | xmake/modules/private/action/build/pcheader.lua | 16 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/actions/download.lua | 1 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/actions/download_resources.lua | 1 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/actions/install.lua | 57 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/actions/patch_sources.lua | 1 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/install_packages.lua | 25 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/package.lua | 148 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/repository.lua | 8 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/install.lua | 9 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/search.lua | 8 | ||||
| -rw-r--r-- | xmake/modules/private/check/checkers/api/package/kind.lua | 4 | ||||
| -rw-r--r-- | xmake/modules/private/utils/batchcmds.lua | 30 | ||||
| -rw-r--r-- | xmake/modules/private/utils/toolchain.lua | 54 | ||||
| -rw-r--r-- | xmake/modules/private/xrepo/action/install.lua | 9 | ||||
| -rw-r--r-- | xmake/modules/private/xrepo/action/remove.lua | 18 | ||||
| -rw-r--r-- | xmake/modules/private/xrepo/action/search.lua | 6 | ||||
| -rw-r--r-- | xmake/modules/private/xrepo/quick_search/cache.lua | 68 | ||||
| -rw-r--r-- | xmake/platforms/bsd/xmake.lua | 4 | ||||
| -rw-r--r-- | xmake/platforms/cross/xmake.lua | 4 | ||||
| -rw-r--r-- | xmake/platforms/linux/xmake.lua | 2 | ||||
| -rw-r--r-- | xmake/platforms/solaris/xmake.lua | 4 | ||||
| -rw-r--r-- | xmake/plugins/doxygen/main.lua | 4 | ||||
| -rw-r--r-- | xmake/plugins/format/main.lua | 4 | ||||
| -rw-r--r-- | xmake/plugins/macro/main.lua | 4 | ||||
| -rw-r--r-- | xmake/plugins/pack/wix/main.lua | 2 | ||||
| -rw-r--r-- | xmake/plugins/plugin/main.lua | 315 | ||||
| -rw-r--r-- | xmake/plugins/plugin/xmake.lua | 17 | ||||
| -rw-r--r-- | xmake/plugins/project/clang/compile_commands.lua | 11 | ||||
| -rw-r--r-- | xmake/plugins/project/ninja/build_ninja.lua | 3 | ||||
| -rw-r--r-- | xmake/plugins/project/utils/target_cmds.lua | 3 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/builder.lua | 27 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/clang/scanner.lua | 5 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/clang/support.lua | 53 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/support.lua | 10 | ||||
| -rw-r--r-- | xmake/rules/utils/bin2c/utils.lua | 12 | ||||
| -rw-r--r-- | xmake/rules/utils/bin2c/xmake.lua | 2 | ||||
| -rw-r--r-- | xmake/rules/utils/bin2obj/utils.lua | 14 | ||||
| -rw-r--r-- | xmake/rules/utils/bin2obj/xmake.lua | 6 | ||||
| -rw-r--r-- | xmake/rules/utils/glsl2spv/xmake.lua | 3 | ||||
| -rw-r--r-- | xmake/rules/utils/hlsl2spv/xmake.lua | 3 | ||||
| -rw-r--r-- | xmake/templates/c++/console/src/main.cpp (renamed from xmake/repository/templates/c++/console/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/console/xmake.lua (renamed from xmake/repository/templates/c++/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/binary/.gitignore (renamed from xmake/repository/templates/c++/module/binary/.gitignore) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/binary/modules/binary/bar/.gitignore (renamed from xmake/repository/templates/c++/module/binary/modules/binary/bar/.gitignore) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/binary/modules/binary/bar/src/add.cpp (renamed from xmake/repository/templates/c++/module/binary/modules/binary/bar/src/add.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/binary/modules/binary/bar/src/sub.cpp (renamed from xmake/repository/templates/c++/module/binary/modules/binary/bar/src/sub.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/binary/modules/binary/bar/xmake.lua (renamed from xmake/repository/templates/c++/module/binary/modules/binary/bar/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/binary/src/main.cpp (renamed from xmake/repository/templates/c++/module/binary/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/binary/xmake.lua (renamed from xmake/repository/templates/c++/module/binary/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/shared/.gitignore (renamed from xmake/repository/templates/c++/module/shared/.gitignore) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/shared/modules/shared/foo/src/foo.cpp (renamed from xmake/repository/templates/c++/module/shared/modules/shared/foo/src/foo.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/shared/modules/shared/foo/xmake.lua (renamed from xmake/repository/templates/c++/module/shared/modules/shared/foo/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/shared/src/main.cpp (renamed from xmake/repository/templates/c++/module/shared/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/module/shared/xmake.lua (renamed from xmake/repository/templates/c++/module/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/console/src/main.cpp (renamed from xmake/repository/templates/c++/qt/console/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/console/xmake.lua (renamed from xmake/repository/templates/c++/qt/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/quickapp/src/main.cpp (renamed from xmake/repository/templates/c++/qt/quickapp/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/quickapp/src/main.qml (renamed from xmake/repository/templates/c++/qt/quickapp/src/main.qml) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/quickapp/src/qml.qrc (renamed from xmake/repository/templates/c++/qt/quickapp/src/qml.qrc) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/quickapp/xmake.lua (renamed from xmake/repository/templates/c++/qt/quickapp/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/quickapp_static/src/main.cpp (renamed from xmake/repository/templates/c++/qt/quickapp_static/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/quickapp_static/src/main.qml (renamed from xmake/repository/templates/c++/qt/quickapp_static/src/main.qml) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/quickapp_static/src/qml.qrc (renamed from xmake/repository/templates/c++/qt/quickapp_static/src/qml.qrc) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/quickapp_static/xmake.lua (renamed from xmake/repository/templates/c++/qt/quickapp_static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/shared/src/demo.cpp (renamed from xmake/repository/templates/c++/qt/shared/src/demo.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/shared/src/demo.h (renamed from xmake/repository/templates/c++/qt/shared/src/demo.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/shared/src/demo_global.h (renamed from xmake/repository/templates/c++/qt/shared/src/demo_global.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/shared/xmake.lua (renamed from xmake/repository/templates/c++/qt/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/static/src/demo.cpp (renamed from xmake/repository/templates/c++/qt/static/src/demo.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/static/src/demo.h (renamed from xmake/repository/templates/c++/qt/static/src/demo.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/static/xmake.lua (renamed from xmake/repository/templates/c++/qt/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp/src/main.cpp (renamed from xmake/repository/templates/c++/qt/widgetapp/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp/src/mainwindow.cpp (renamed from xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp/src/mainwindow.h (renamed from xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp/src/mainwindow.ui (renamed from xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.ui) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp/xmake.lua (renamed from xmake/repository/templates/c++/qt/widgetapp/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp_static/src/main.cpp (renamed from xmake/repository/templates/c++/qt/widgetapp_static/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp_static/src/mainwindow.cpp (renamed from xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp_static/src/mainwindow.h (renamed from xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp_static/src/mainwindow.ui (renamed from xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.ui) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/qt/widgetapp_static/xmake.lua (renamed from xmake/repository/templates/c++/qt/widgetapp_static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/shared/src/foo.cpp (renamed from xmake/repository/templates/c++/shared/src/foo.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/shared/src/foo.h (renamed from xmake/repository/templates/c++/shared/src/foo.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/shared/src/main.cpp (renamed from xmake/repository/templates/c++/shared/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/shared/xmake.lua (renamed from xmake/repository/templates/c++/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/static/src/foo.cpp (renamed from xmake/repository/templates/c++/static/src/foo.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/static/src/foo.h (renamed from xmake/repository/templates/c++/static/src/foo.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/static/src/main.cpp (renamed from xmake/repository/templates/c++/static/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/static/xmake.lua (renamed from xmake/repository/templates/c++/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/wxwidgets/src/main.cpp (renamed from xmake/repository/templates/c++/wxwidgets/src/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/wxwidgets/xmake.lua (renamed from xmake/repository/templates/c++/wxwidgets/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/xmake/cli/src/lni/main.cpp (renamed from xmake/repository/templates/c++/xmake/cli/src/lni/main.cpp) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/xmake/cli/src/lua/main.lua (renamed from xmake/repository/templates/c++/xmake/cli/src/lua/main.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c++/xmake/cli/xmake.lua (renamed from xmake/repository/templates/c++/xmake/cli/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/console/src/main.c (renamed from xmake/repository/templates/c/console/src/main.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/console/xmake.lua (renamed from xmake/repository/templates/c/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/binary/.gitignore (renamed from xmake/repository/templates/c/module/binary/.gitignore) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/binary/modules/binary/bar/.gitignore (renamed from xmake/repository/templates/c/module/binary/modules/binary/bar/.gitignore) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/binary/modules/binary/bar/src/add.c (renamed from xmake/repository/templates/c/module/binary/modules/binary/bar/src/add.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/binary/modules/binary/bar/src/sub.c (renamed from xmake/repository/templates/c/module/binary/modules/binary/bar/src/sub.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/binary/modules/binary/bar/xmake.lua (renamed from xmake/repository/templates/c/module/binary/modules/binary/bar/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/binary/src/main.c (renamed from xmake/repository/templates/c/module/binary/src/main.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/binary/xmake.lua (renamed from xmake/repository/templates/c/module/binary/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/shared/.gitignore (renamed from xmake/repository/templates/c/module/shared/.gitignore) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/shared/modules/shared/foo/src/foo.c (renamed from xmake/repository/templates/c/module/shared/modules/shared/foo/src/foo.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/shared/modules/shared/foo/xmake.lua (renamed from xmake/repository/templates/c/module/shared/modules/shared/foo/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/shared/src/main.c (renamed from xmake/repository/templates/c/module/shared/src/main.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/module/shared/xmake.lua (renamed from xmake/repository/templates/c/module/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/shared/src/foo.c (renamed from xmake/repository/templates/c/shared/src/foo.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/shared/src/foo.h (renamed from xmake/repository/templates/c/shared/src/foo.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/shared/src/main.c (renamed from xmake/repository/templates/c/shared/src/main.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/shared/xmake.lua (renamed from xmake/repository/templates/c/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/static/src/foo.c (renamed from xmake/repository/templates/c/static/src/foo.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/static/src/foo.h (renamed from xmake/repository/templates/c/static/src/foo.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/static/src/main.c (renamed from xmake/repository/templates/c/static/src/main.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/static/xmake.lua (renamed from xmake/repository/templates/c/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/xmake/cli/src/lni/main.c (renamed from xmake/repository/templates/c/xmake/cli/src/lni/main.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/xmake/cli/src/lua/main.lua (renamed from xmake/repository/templates/c/xmake/cli/src/lua/main.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/c/xmake/cli/xmake.lua (renamed from xmake/repository/templates/c/xmake/cli/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/csharp/console/src/Program.cs (renamed from xmake/repository/templates/csharp/console/src/Program.cs) | 0 | ||||
| -rw-r--r-- | xmake/templates/csharp/console/xmake.lua (renamed from xmake/repository/templates/csharp/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/csharp/shared/src/foo.cs (renamed from xmake/repository/templates/csharp/shared/src/foo.cs) | 0 | ||||
| -rw-r--r-- | xmake/templates/csharp/shared/src/main.cs (renamed from xmake/repository/templates/csharp/shared/src/main.cs) | 0 | ||||
| -rw-r--r-- | xmake/templates/csharp/shared/xmake.lua (renamed from xmake/repository/templates/csharp/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/csharp/static/src/foo.cs (renamed from xmake/repository/templates/csharp/static/src/foo.cs) | 0 | ||||
| -rw-r--r-- | xmake/templates/csharp/static/src/main.cs (renamed from xmake/repository/templates/csharp/static/src/main.cs) | 0 | ||||
| -rw-r--r-- | xmake/templates/csharp/static/xmake.lua (renamed from xmake/repository/templates/csharp/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/cuda/console/src/main.cu (renamed from xmake/repository/templates/cuda/console/src/main.cu) | 0 | ||||
| -rw-r--r-- | xmake/templates/cuda/console/xmake.lua (renamed from xmake/repository/templates/cuda/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/cuda/shared/inc/lib.cuh (renamed from xmake/repository/templates/cuda/shared/inc/lib.cuh) | 0 | ||||
| -rw-r--r-- | xmake/templates/cuda/shared/src/lib.cu (renamed from xmake/repository/templates/cuda/shared/src/lib.cu) | 0 | ||||
| -rw-r--r-- | xmake/templates/cuda/shared/xmake.lua (renamed from xmake/repository/templates/cuda/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/cuda/static/inc/lib.cuh (renamed from xmake/repository/templates/cuda/static/inc/lib.cuh) | 0 | ||||
| -rw-r--r-- | xmake/templates/cuda/static/src/lib.cu (renamed from xmake/repository/templates/cuda/static/src/lib.cu) | 0 | ||||
| -rw-r--r-- | xmake/templates/cuda/static/xmake.lua (renamed from xmake/repository/templates/cuda/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/dlang/console/src/main.d (renamed from xmake/repository/templates/dlang/console/src/main.d) | 0 | ||||
| -rw-r--r-- | xmake/templates/dlang/console/xmake.lua (renamed from xmake/repository/templates/dlang/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/dlang/shared/src/interfaces.d (renamed from xmake/repository/templates/dlang/shared/src/interfaces.d) | 0 | ||||
| -rw-r--r-- | xmake/templates/dlang/shared/src/main.d (renamed from xmake/repository/templates/dlang/shared/src/main.d) | 0 | ||||
| -rw-r--r-- | xmake/templates/dlang/shared/xmake.lua (renamed from xmake/repository/templates/dlang/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/dlang/static/src/interfaces.d (renamed from xmake/repository/templates/dlang/static/src/interfaces.d) | 0 | ||||
| -rw-r--r-- | xmake/templates/dlang/static/src/main.d (renamed from xmake/repository/templates/dlang/static/src/main.d) | 0 | ||||
| -rw-r--r-- | xmake/templates/dlang/static/xmake.lua (renamed from xmake/repository/templates/dlang/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/fortran/console/src/main.f90 (renamed from xmake/repository/templates/fortran/console/src/main.f90) | 0 | ||||
| -rw-r--r-- | xmake/templates/fortran/console/xmake.lua (renamed from xmake/repository/templates/fortran/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/fortran/shared/src/main.f90 (renamed from xmake/repository/templates/fortran/shared/src/main.f90) | 0 | ||||
| -rw-r--r-- | xmake/templates/fortran/shared/src/test.f90 (renamed from xmake/repository/templates/fortran/shared/src/test.f90) | 0 | ||||
| -rw-r--r-- | xmake/templates/fortran/shared/xmake.lua (renamed from xmake/repository/templates/fortran/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/fortran/static/src/main.f90 (renamed from xmake/repository/templates/fortran/static/src/main.f90) | 0 | ||||
| -rw-r--r-- | xmake/templates/fortran/static/src/test.f90 (renamed from xmake/repository/templates/fortran/static/src/test.f90) | 0 | ||||
| -rw-r--r-- | xmake/templates/fortran/static/xmake.lua (renamed from xmake/repository/templates/fortran/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/go/console/src/main.go (renamed from xmake/repository/templates/go/console/src/main.go) | 0 | ||||
| -rw-r--r-- | xmake/templates/go/console/xmake.lua (renamed from xmake/repository/templates/go/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/go/static/src/main.go (renamed from xmake/repository/templates/go/static/src/main.go) | 0 | ||||
| -rw-r--r-- | xmake/templates/go/static/src/module/add.go (renamed from xmake/repository/templates/go/static/src/module/add.go) | 0 | ||||
| -rw-r--r-- | xmake/templates/go/static/src/module/sub.go (renamed from xmake/repository/templates/go/static/src/module/sub.go) | 0 | ||||
| -rw-r--r-- | xmake/templates/go/static/src/test.go (renamed from xmake/repository/templates/go/static/src/test.go) | 0 | ||||
| -rw-r--r-- | xmake/templates/go/static/xmake.lua (renamed from xmake/repository/templates/go/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/kotlin/console/src/main.kt (renamed from xmake/repository/templates/kotlin/console/src/main.kt) | 0 | ||||
| -rw-r--r-- | xmake/templates/kotlin/console/xmake.lua (renamed from xmake/repository/templates/kotlin/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/kotlin/shared/src/foo.kt (renamed from xmake/repository/templates/kotlin/shared/src/foo.kt) | 0 | ||||
| -rw-r--r-- | xmake/templates/kotlin/shared/src/main.c (renamed from xmake/repository/templates/kotlin/shared/src/main.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/kotlin/shared/xmake.lua (renamed from xmake/repository/templates/kotlin/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/kotlin/static/src/foo.kt (renamed from xmake/repository/templates/kotlin/static/src/foo.kt) | 0 | ||||
| -rw-r--r-- | xmake/templates/kotlin/static/src/main.c (renamed from xmake/repository/templates/kotlin/static/src/main.c) | 0 | ||||
| -rw-r--r-- | xmake/templates/kotlin/static/xmake.lua (renamed from xmake/repository/templates/kotlin/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/nim/console/src/main.nim (renamed from xmake/repository/templates/nim/console/src/main.nim) | 0 | ||||
| -rw-r--r-- | xmake/templates/nim/console/xmake.lua (renamed from xmake/repository/templates/nim/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/nim/shared/src/foo.nim (renamed from xmake/repository/templates/nim/shared/src/foo.nim) | 0 | ||||
| -rw-r--r-- | xmake/templates/nim/shared/src/main.nim (renamed from xmake/repository/templates/nim/shared/src/main.nim) | 0 | ||||
| -rw-r--r-- | xmake/templates/nim/shared/xmake.lua (renamed from xmake/repository/templates/nim/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/nim/static/src/foo.nim (renamed from xmake/repository/templates/nim/static/src/foo.nim) | 0 | ||||
| -rw-r--r-- | xmake/templates/nim/static/src/main.nim (renamed from xmake/repository/templates/nim/static/src/main.nim) | 0 | ||||
| -rw-r--r-- | xmake/templates/nim/static/xmake.lua (renamed from xmake/repository/templates/nim/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/console/src/main.mm (renamed from xmake/repository/templates/objc++/console/src/main.mm) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/console/xmake.lua (renamed from xmake/repository/templates/objc++/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/xcode/bundle/src/Info.plist (renamed from xmake/repository/templates/objc++/xcode/bundle/src/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/xcode/bundle/src/test.h (renamed from xmake/repository/templates/objc++/xcode/bundle/src/test.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/xcode/bundle/src/test.mm (renamed from xmake/repository/templates/objc++/xcode/bundle/src/test.mm) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/xcode/bundle/xmake.lua (renamed from xmake/repository/templates/objc++/xcode/bundle/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/xcode/framework/src/Info.plist (renamed from xmake/repository/templates/objc++/xcode/framework/src/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/xcode/framework/src/test.h (renamed from xmake/repository/templates/objc++/xcode/framework/src/test.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/xcode/framework/src/test.mm (renamed from xmake/repository/templates/objc++/xcode/framework/src/test.mm) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc++/xcode/framework/xmake.lua (renamed from xmake/repository/templates/objc++/xcode/framework/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/console/src/main.m (renamed from xmake/repository/templates/objc/console/src/main.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/console/xmake.lua (renamed from xmake/repository/templates/objc/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/bundle/src/Info.plist (renamed from xmake/repository/templates/objc/xcode/bundle/src/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/bundle/src/test.h (renamed from xmake/repository/templates/objc/xcode/bundle/src/test.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/bundle/src/test.m (renamed from xmake/repository/templates/objc/xcode/bundle/src/test.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/bundle/xmake.lua (renamed from xmake/repository/templates/objc/xcode/bundle/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/framework/src/Info.plist (renamed from xmake/repository/templates/objc/xcode/framework/src/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/framework/src/test.h (renamed from xmake/repository/templates/objc/xcode/framework/src/test.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/framework/src/test.m (renamed from xmake/repository/templates/objc/xcode/framework/src/test.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/framework/xmake.lua (renamed from xmake/repository/templates/objc/xcode/framework/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/AppDelegate.h (renamed from xmake/repository/templates/objc/xcode/iosapp/src/AppDelegate.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/AppDelegate.m (renamed from xmake/repository/templates/objc/xcode/iosapp/src/AppDelegate.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json (renamed from xmake/repository/templates/objc/xcode/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/Assets.xcassets/Contents.json (renamed from xmake/repository/templates/objc/xcode/iosapp/src/Assets.xcassets/Contents.json) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/Base.lproj/LaunchScreen.storyboard (renamed from xmake/repository/templates/objc/xcode/iosapp/src/Base.lproj/LaunchScreen.storyboard) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/Base.lproj/Main.storyboard (renamed from xmake/repository/templates/objc/xcode/iosapp/src/Base.lproj/Main.storyboard) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/Info.plist (renamed from xmake/repository/templates/objc/xcode/iosapp/src/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/SceneDelegate.h (renamed from xmake/repository/templates/objc/xcode/iosapp/src/SceneDelegate.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/SceneDelegate.m (renamed from xmake/repository/templates/objc/xcode/iosapp/src/SceneDelegate.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/ViewController.h (renamed from xmake/repository/templates/objc/xcode/iosapp/src/ViewController.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/ViewController.m (renamed from xmake/repository/templates/objc/xcode/iosapp/src/ViewController.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/src/main.m (renamed from xmake/repository/templates/objc/xcode/iosapp/src/main.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp/xmake.lua (renamed from xmake/repository/templates/objc/xcode/iosapp/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.h (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.m (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/Contents.json (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/Contents.json) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/Main.storyboard (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/Main.storyboard) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/Info.plist (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.h (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.m (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.h (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.m (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/app/main.m (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/main.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/framework/Info.plist (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/framework/test.h (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/test.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/src/framework/test.m (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/test.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/iosapp_with_framework/xmake.lua (renamed from xmake/repository/templates/objc/xcode/iosapp_with_framework/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/AppDelegate.h (renamed from xmake/repository/templates/objc/xcode/macapp/src/AppDelegate.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/AppDelegate.m (renamed from xmake/repository/templates/objc/xcode/macapp/src/AppDelegate.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json (renamed from xmake/repository/templates/objc/xcode/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/Assets.xcassets/Contents.json (renamed from xmake/repository/templates/objc/xcode/macapp/src/Assets.xcassets/Contents.json) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/Base.lproj/Main.storyboard (renamed from xmake/repository/templates/objc/xcode/macapp/src/Base.lproj/Main.storyboard) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/Info.plist (renamed from xmake/repository/templates/objc/xcode/macapp/src/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/ViewController.h (renamed from xmake/repository/templates/objc/xcode/macapp/src/ViewController.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/ViewController.m (renamed from xmake/repository/templates/objc/xcode/macapp/src/ViewController.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/main.m (renamed from xmake/repository/templates/objc/xcode/macapp/src/main.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/src/test.entitlements (renamed from xmake/repository/templates/objc/xcode/macapp/src/test.entitlements) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp/xmake.lua (renamed from xmake/repository/templates/objc/xcode/macapp/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.h (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.m (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/Contents.json (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/Contents.json) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/Base.lproj/Main.storyboard (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Base.lproj/Main.storyboard) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/Info.plist (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/ViewController.h (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/ViewController.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/ViewController.m (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/ViewController.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/main.m (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/main.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/app/test.entitlements (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/test.entitlements) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/framework/Info.plist (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/Info.plist) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/framework/test.h (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/test.h) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/src/framework/test.m (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/test.m) | 0 | ||||
| -rw-r--r-- | xmake/templates/objc/xcode/macapp_with_framework/xmake.lua (renamed from xmake/repository/templates/objc/xcode/macapp_with_framework/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/pascal/console/src/main.pas (renamed from xmake/repository/templates/pascal/console/src/main.pas) | 0 | ||||
| -rw-r--r-- | xmake/templates/pascal/console/xmake.lua (renamed from xmake/repository/templates/pascal/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/pascal/shared/src/foo.pas (renamed from xmake/repository/templates/pascal/shared/src/foo.pas) | 0 | ||||
| -rw-r--r-- | xmake/templates/pascal/shared/src/main.pas (renamed from xmake/repository/templates/pascal/shared/src/main.pas) | 0 | ||||
| -rw-r--r-- | xmake/templates/pascal/shared/xmake.lua (renamed from xmake/repository/templates/pascal/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/rust/console/src/main.rs (renamed from xmake/repository/templates/rust/console/src/main.rs) | 0 | ||||
| -rw-r--r-- | xmake/templates/rust/console/xmake.lua (renamed from xmake/repository/templates/rust/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/rust/shared/src/foo.rs (renamed from xmake/repository/templates/rust/shared/src/foo.rs) | 0 | ||||
| -rw-r--r-- | xmake/templates/rust/shared/src/main.rs (renamed from xmake/repository/templates/rust/shared/src/main.rs) | 0 | ||||
| -rw-r--r-- | xmake/templates/rust/shared/xmake.lua (renamed from xmake/repository/templates/rust/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/rust/static/src/foo.rs (renamed from xmake/repository/templates/rust/static/src/foo.rs) | 0 | ||||
| -rw-r--r-- | xmake/templates/rust/static/src/main.rs (renamed from xmake/repository/templates/rust/static/src/main.rs) | 0 | ||||
| -rw-r--r-- | xmake/templates/rust/static/xmake.lua (renamed from xmake/repository/templates/rust/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/swift/console/src/main.swift (renamed from xmake/repository/templates/swift/console/src/main.swift) | 0 | ||||
| -rw-r--r-- | xmake/templates/swift/console/xmake.lua (renamed from xmake/repository/templates/swift/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/vala/console/src/main.vala (renamed from xmake/repository/templates/vala/console/src/main.vala) | 0 | ||||
| -rw-r--r-- | xmake/templates/vala/console/xmake.lua (renamed from xmake/repository/templates/vala/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/vala/shared/src/main.vala (renamed from xmake/repository/templates/vala/shared/src/main.vala) | 0 | ||||
| -rw-r--r-- | xmake/templates/vala/shared/src/mymath.vala (renamed from xmake/repository/templates/vala/shared/src/mymath.vala) | 0 | ||||
| -rw-r--r-- | xmake/templates/vala/shared/xmake.lua (renamed from xmake/repository/templates/vala/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/vala/static/src/main.vala (renamed from xmake/repository/templates/vala/static/src/main.vala) | 0 | ||||
| -rw-r--r-- | xmake/templates/vala/static/src/mymath.vala (renamed from xmake/repository/templates/vala/static/src/mymath.vala) | 0 | ||||
| -rw-r--r-- | xmake/templates/vala/static/xmake.lua (renamed from xmake/repository/templates/vala/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/zig/console/src/main.zig (renamed from xmake/repository/templates/zig/console/src/main.zig) | 0 | ||||
| -rw-r--r-- | xmake/templates/zig/console/xmake.lua (renamed from xmake/repository/templates/zig/console/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/zig/shared/src/main.zig (renamed from xmake/repository/templates/zig/shared/src/main.zig) | 0 | ||||
| -rw-r--r-- | xmake/templates/zig/shared/src/test.zig (renamed from xmake/repository/templates/zig/shared/src/test.zig) | 0 | ||||
| -rw-r--r-- | xmake/templates/zig/shared/xmake.lua (renamed from xmake/repository/templates/zig/shared/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/templates/zig/static/src/main.zig (renamed from xmake/repository/templates/zig/static/src/main.zig) | 0 | ||||
| -rw-r--r-- | xmake/templates/zig/static/src/test.zig (renamed from xmake/repository/templates/zig/static/src/test.zig) | 0 | ||||
| -rw-r--r-- | xmake/templates/zig/static/xmake.lua (renamed from xmake/repository/templates/zig/static/xmake.lua) | 0 | ||||
| -rw-r--r-- | xmake/toolchains/emcc/xmake.lua | 28 | ||||
| -rw-r--r-- | xmake/toolchains/mingw/xmake.lua | 2 |
429 files changed, 5575 insertions, 545 deletions
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 2bb1b81ea..5bbc0f047 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -62,12 +62,11 @@ jobs: sudo apt install -y dh-make rng-tools devscripts lintian echo "$PPA_GPG_PRIKEY_2C0C68C9" > ppa_gpg.key gpg --import ppa_gpg.key - scripts/makeppa questing # 25.10 - scripts/makeppa plucky # 25.04 + # @note only the series which are not obsolete on launchpad can be uploaded, + # @see https://api.launchpad.net/1.0/ubuntu/series + scripts/makeppa stonking # 26.10 + scripts/makeppa resolute # 26.04 scripts/makeppa noble # 24.04 - scripts/makeppa mantic # 23.10 - scripts/makeppa lunar # 23.04 - scripts/makeppa kinetic # 22.10 scripts/makeppa jammy # 22.04 scripts/makeppa focal # 20.04 scripts/makeppa bionic # 18.04 diff --git a/CHANGELOG.md b/CHANGELOG.md index 616ce7947..52dc9bdc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,112 @@ ## master (unreleased) +## v3.1.1 + +### New features + +* [#7696](https://github.com/xmake-io/xmake/pull/7696): Add addons support, to extend xmake with plugins, rules, toolchains, templates, modules and includes files +* [#7702](https://github.com/xmake-io/xmake/pull/7702): Auto-install the addons declared by a project and lock them in `xmake-addons.lock` +* [#7714](https://github.com/xmake-io/xmake/pull/7714): Support `add_addons(...)` in `xmake.lua` +* [#7706](https://github.com/xmake-io/xmake/pull/7706): Add tests for addons +* [#7707](https://github.com/xmake-io/xmake/pull/7707): Add tests for the package definitions shipped by addons +* [#7717](https://github.com/xmake-io/xmake/pull/7717): Move the `format` / `doxygen` / `macro` plugins to addons +* [#7723](https://github.com/xmake-io/xmake/pull/7723): Add new cross-compilation architectures, e.g. SPARC64 +* [#7721](https://github.com/xmake-io/xmake/pull/7721): Add the `package.host.install_locally` policy +* [#7699](https://github.com/xmake-io/xmake/pull/7699): Rework the templates directory and template distribution +* Add the `pkg` package manager for BSD + +### Changes + +* [#7719](https://github.com/xmake-io/xmake/pull/7719): Propagate the vector extensions of a package to its consumers +* [#7713](https://github.com/xmake-io/xmake/pull/7713): Run `hlsl2spv` / `glsl2spv` before the C++ module scan +* [#7722](https://github.com/xmake-io/xmake/pull/7722): Improve the interpreter, project loading, search cache and semver +* [#7733](https://github.com/xmake-io/xmake/pull/7733): Check the name conflicts of the global modules of addons +* [#7726](https://github.com/xmake-io/xmake/pull/7726): Improve the mingw toolchain for clang and libc++ + +### Bugs fixed + +* [#7737](https://github.com/xmake-io/xmake/pull/7737): Fix the duplicated packages of the nested builds when installing them locally +* [#7738](https://github.com/xmake-io/xmake/issues/7738): Fix the platform menu of the remote build, e.g. `xmake f -p windows --wdk=xxx` +* [#7710](https://github.com/xmake-io/xmake/pull/7710): Fix the link name of libraries ending with `.lib` +* [#7709](https://github.com/xmake-io/xmake/pull/7709): Fix the runtime flags of clang +* [#7703](https://github.com/xmake-io/xmake/pull/7703): Fix wix to recognize `x86_64` when passing `-arch` +* [#7701](https://github.com/xmake-io/xmake/pull/7701): Fix the dependency check to detect appended nested values +* [#7698](https://github.com/xmake-io/xmake/pull/7698): Fix the semver version selection and build metadata sorting +* Fix `scheduler.co_resume` to raise the errors of the resumed coroutine + +## v3.1.0 + +### New features + +* [#7558](https://github.com/xmake-io/xmake/pull/7558): Add `check_alignof` / `alignof` detection support +* [#7587](https://github.com/xmake-io/xmake/pull/7587): Support `xmake show --format=json` +* [#7607](https://github.com/xmake-io/xmake/pull/7607): Support passing multiple target names to `build` / `clean` and other commands +* [#7634](https://github.com/xmake-io/xmake/pull/7634): Add filter support for xpack +* [#7654](https://github.com/xmake-io/xmake/pull/7654): Add `batchcmds:call` and lua-file transform support for `bin2obj` / `bin2c` +* [#7680](https://github.com/xmake-io/xmake/pull/7680): Rework `xmake plugin` to install plugins from repositories (`repo@name` or name), git urls (`github:user/repo[#branch]`) and local directories using the packages-style `plugins/<first-letter>/<name>` layout, and list built-in / installed / available plugins with their descriptions +* Add gcc-16 toolchain support + +### Changes + +* [#7562](https://github.com/xmake-io/xmake/pull/7562): Improve nuget version handling +* [#7564](https://github.com/xmake-io/xmake/pull/7564): Improve vcpkg dependency info in `find_package` +* [#7582](https://github.com/xmake-io/xmake/pull/7582): Support `set_encodings` and filter output for nvcc +* [#7609](https://github.com/xmake-io/xmake/pull/7609): Use `FormatMessageW` for Windows system error messages +* [#7614](https://github.com/xmake-io/xmake/pull/7614): Improve `cargo` package installation +* [#7619](https://github.com/xmake-io/xmake/pull/7619): Work around clangd drive-letter casing issue +* [#7620](https://github.com/xmake-io/xmake/pull/7620): Improve cl flag detection and output handling on vs2015 +* [#7625](https://github.com/xmake-io/xmake/pull/7625): Improve verilator rules +* [#7629](https://github.com/xmake-io/xmake/pull/7629): vsxmake: support custom source types in the solution explorer and nonetype targets +* [#7630](https://github.com/xmake-io/xmake/pull/7630): Add `add_toolset` api checker +* [#7637](https://github.com/xmake-io/xmake/pull/7637): Improve readline / curses options for mingw +* [#7648](https://github.com/xmake-io/xmake/pull/7648): Improve error tips +* [#7655](https://github.com/xmake-io/xmake/pull/7655): Improve bin2obj object-flag detection and add ppc / mips support +* [#7657](https://github.com/xmake-io/xmake/pull/7657): Update NDK sdkver for riscv64 +* [#7666](https://github.com/xmake-io/xmake/pull/7666): Improve vcpkg package discovery +* [#7672](https://github.com/xmake-io/xmake/pull/7672): Add fallback download support +* [#7688](https://github.com/xmake-io/xmake/pull/7688): Improve static libc++ runtime links for clang +* [#7689](https://github.com/xmake-io/xmake/pull/7689): Rewrite `xmake plugin --install` to install plugins from xmake-repo as `plugin` kind packages, reusing the package installation flow +* [#7693](https://github.com/xmake-io/xmake/pull/7693): Replace the deprecated tbox interfaces +* Improve elf rpath cleaning and package path handling +* Add xcodebuild detection +* Update the bundled tbox + +### Bugs fixed + +* [#7561](https://github.com/xmake-io/xmake/pull/7561): Fix `-flto=thin` regression for clang-cl +* [#7563](https://github.com/xmake-io/xmake/pull/7563): Fix crash in `contains` and improve PCH for C++ std modules +* [#7580](https://github.com/xmake-io/xmake/pull/7580): Fix the format plugin when the header path is already absolute +* [#7581](https://github.com/xmake-io/xmake/pull/7581): Fix missing paren in package loading +* [#7583](https://github.com/xmake-io/xmake/pull/7583): Fix splitting global flags for cmake packages +* [#7599](https://github.com/xmake-io/xmake/pull/7599): Fix gzip / tar detection on OpenBSD +* [#7600](https://github.com/xmake-io/xmake/pull/7600): Fix enabling the build cache memcache +* [#7601](https://github.com/xmake-io/xmake/pull/7601): Fix verilator to always define `TRACE` +* [#7602](https://github.com/xmake-io/xmake/pull/7602): Fix package load memcache +* [#7603](https://github.com/xmake-io/xmake/pull/7603): Fix `rmdir` via tbox update +* [#7604](https://github.com/xmake-io/xmake/pull/7604): Fix rpath cleaning for elf +* [#7608](https://github.com/xmake-io/xmake/pull/7608): Fix typos and format command menus +* [#7611](https://github.com/xmake-io/xmake/pull/7611): Fix cache environment variable handling ([#7576](https://github.com/xmake-io/xmake/issues/7576)) +* [#7622](https://github.com/xmake-io/xmake/pull/7622): Fix default maintainer for deb packaging +* [#7627](https://github.com/xmake-io/xmake/pull/7627): Fix PATH handling in debuild +* [#7631](https://github.com/xmake-io/xmake/pull/7631): Fix PATH handling when installing deb packages +* [#7633](https://github.com/xmake-io/xmake/pull/7633): Fix pkg-config path for BSD in the Meson backend +* [#7640](https://github.com/xmake-io/xmake/pull/7640): Improve emcc detection with a fallback search +* [#7644](https://github.com/xmake-io/xmake/pull/7644): Fix stack buffer overflow for long paths in path translation +* [#7645](https://github.com/xmake-io/xmake/pull/7645): Fix removing read-only directories +* [#7659](https://github.com/xmake-io/xmake/pull/7659): Fix emcc detection for `.exe` / `.bat` on Windows +* [#7661](https://github.com/xmake-io/xmake/pull/7661): Revert static libc++ link for clang +* [#7668](https://github.com/xmake-io/xmake/pull/7668): Fix passing paths to cmake +* [#7671](https://github.com/xmake-io/xmake/pull/7671): Fix tbox bugs +* [#7674](https://github.com/xmake-io/xmake/pull/7674): Fix Mach host send-right leaks on macOS +* [#7676](https://github.com/xmake-io/xmake/pull/7676): Fix masm symbol flags for embed / edit levels +* [#7679](https://github.com/xmake-io/xmake/pull/7679): Fix `set_pcheader` for msvc in C mode +* [#7684](https://github.com/xmake-io/xmake/pull/7684): Fix wrong Lua stack index in `process.open` +* [#7685](https://github.com/xmake-io/xmake/pull/7685): Fix engine resource leaks +* [#7687](https://github.com/xmake-io/xmake/pull/7687): Fix the ninja generator to emit build edges for `win.sdk.resource` source batches ([#7682](https://github.com/xmake-io/xmake/issues/7682)) +* [#7692](https://github.com/xmake-io/xmake/pull/7692): Fix dependency order for `build.c++.modules.tryreuse` +* Fix trybuild for scons + ## v3.0.9 ### New features @@ -2418,6 +2524,112 @@ ## master (开发中) +## v3.1.1 + +### 新特性 + +* [#7696](https://github.com/xmake-io/xmake/pull/7696): 添加 addons 支持,可以用插件、规则、工具链、模板、模块和 includes 文件扩展 xmake +* [#7702](https://github.com/xmake-io/xmake/pull/7702): 自动安装工程声明的 addon,并用 `xmake-addons.lock` 锁定版本 +* [#7714](https://github.com/xmake-io/xmake/pull/7714): 支持在 `xmake.lua` 中使用 `add_addons(...)` +* [#7706](https://github.com/xmake-io/xmake/pull/7706): 添加 addon 测试 +* [#7707](https://github.com/xmake-io/xmake/pull/7707): 添加 addon 分发 package 定义的测试 +* [#7717](https://github.com/xmake-io/xmake/pull/7717): 将 `format` / `doxygen` / `macro` 插件迁移为 addon +* [#7723](https://github.com/xmake-io/xmake/pull/7723): 添加新的交叉编译架构,例如 SPARC64 +* [#7721](https://github.com/xmake-io/xmake/pull/7721): 添加 `package.host.install_locally` 策略 +* [#7699](https://github.com/xmake-io/xmake/pull/7699): 重构模板目录和模板分发 +* 添加 BSD 的 `pkg` 包管理器支持 + +### 改进 + +* [#7719](https://github.com/xmake-io/xmake/pull/7719): 将包的向量扩展配置传递给使用它的目标 +* [#7713](https://github.com/xmake-io/xmake/pull/7713): 让 `hlsl2spv` / `glsl2spv` 在 C++ 模块扫描之前执行 +* [#7722](https://github.com/xmake-io/xmake/pull/7722): 改进 interpreter、工程加载、搜索缓存和 semver +* [#7733](https://github.com/xmake-io/xmake/pull/7733): 检查 addon 全局模块的命名冲突 +* [#7726](https://github.com/xmake-io/xmake/pull/7726): 改进 mingw 工具链对 clang 和 libc++ 的支持 + +### Bug 修复 + +* [#7737](https://github.com/xmake-io/xmake/pull/7737): 修复本地安装包时,嵌套构建重复安装包的问题 +* [#7738](https://github.com/xmake-io/xmake/issues/7738): 修复远程编译下的平台菜单,例如 `xmake f -p windows --wdk=xxx` +* [#7710](https://github.com/xmake-io/xmake/pull/7710): 修复 `.lib` 结尾的库名被错误裁剪的问题 +* [#7709](https://github.com/xmake-io/xmake/pull/7709): 修复 clang 的 runtime flags 检测 +* [#7703](https://github.com/xmake-io/xmake/pull/7703): 修复 wix 传递 `-arch` 时无法识别 `x86_64` 的问题 +* [#7701](https://github.com/xmake-io/xmake/pull/7701): 修复依赖检测无法发现嵌套值追加的问题 +* [#7698](https://github.com/xmake-io/xmake/pull/7698): 修复 semver 的版本选择和 build metadata 排序 +* 修复 `scheduler.co_resume`,让被恢复协程的错误能够正常抛出 + +## v3.1.0 + +### 新特性 + +* [#7558](https://github.com/xmake-io/xmake/pull/7558): 添加 `check_alignof` / `alignof` 检测支持 +* [#7587](https://github.com/xmake-io/xmake/pull/7587): 支持 `xmake show --format=json` +* [#7607](https://github.com/xmake-io/xmake/pull/7607): 支持给 `build` / `clean` 等命令传递多个目标名 +* [#7634](https://github.com/xmake-io/xmake/pull/7634): 为 xpack 添加过滤器支持 +* [#7654](https://github.com/xmake-io/xmake/pull/7654): 为 `bin2obj` / `bin2c` 添加 `batchcmds:call` 和 lua 文件 transform 支持 +* [#7680](https://github.com/xmake-io/xmake/pull/7680): 重构 `xmake plugin`,支持从仓库(`repo@name` 或名称)、git 地址(`github:user/repo[#branch]`)以及本地目录安装插件,仓库中的插件采用与 packages 相同的 `plugins/<首字母>/<名称>` 布局,并列出内置、已安装和仓库中可安装的插件及其描述 +* 添加 gcc-16 工具链支持 + +### 改进 + +* [#7562](https://github.com/xmake-io/xmake/pull/7562): 改进 nuget 版本处理 +* [#7564](https://github.com/xmake-io/xmake/pull/7564): 改进 `find_package` 中的 vcpkg 依赖信息 +* [#7582](https://github.com/xmake-io/xmake/pull/7582): 支持 nvcc 的 `set_encodings` 并过滤其输出 +* [#7609](https://github.com/xmake-io/xmake/pull/7609): 使用 `FormatMessageW` 获取 Windows 系统错误信息 +* [#7614](https://github.com/xmake-io/xmake/pull/7614): 改进 `cargo` 包安装 +* [#7619](https://github.com/xmake-io/xmake/pull/7619): 规避 clangd 盘符大小写问题 +* [#7620](https://github.com/xmake-io/xmake/pull/7620): 改进 vs2015 下 cl 的编译选项检测和输出处理 +* [#7625](https://github.com/xmake-io/xmake/pull/7625): 改进 verilator 规则 +* [#7629](https://github.com/xmake-io/xmake/pull/7629): vsxmake: 支持解决方案资源管理器中的自定义源类型和 nonetype 目标 +* [#7630](https://github.com/xmake-io/xmake/pull/7630): 添加 `add_toolset` api 检查器 +* [#7637](https://github.com/xmake-io/xmake/pull/7637): 改进 mingw 下的 readline / curses 选项 +* [#7648](https://github.com/xmake-io/xmake/pull/7648): 改进错误提示 +* [#7655](https://github.com/xmake-io/xmake/pull/7655): 改进 bin2obj 的目标文件 flag 检测并添加 ppc / mips 支持 +* [#7657](https://github.com/xmake-io/xmake/pull/7657): 更新 riscv64 的 NDK sdkver +* [#7666](https://github.com/xmake-io/xmake/pull/7666): 改进 vcpkg 包查找 +* [#7672](https://github.com/xmake-io/xmake/pull/7672): 添加下载失败回退支持 +* [#7688](https://github.com/xmake-io/xmake/pull/7688): 改进 clang 的静态 libc++ 运行时链接 +* [#7689](https://github.com/xmake-io/xmake/pull/7689): 重写 `xmake plugin --install`,将插件作为 `plugin` 类型的包从 xmake-repo 安装,复用包安装流程 +* [#7693](https://github.com/xmake-io/xmake/pull/7693): 替换 tbox 中已废弃的接口 +* 改进 elf rpath 清理和包路径处理 +* 添加 xcodebuild 检测 +* 更新内置的 tbox + +### Bugs 修复 + +* [#7561](https://github.com/xmake-io/xmake/pull/7561): 修复 clang-cl 的 `-flto=thin` 回归问题 +* [#7563](https://github.com/xmake-io/xmake/pull/7563): 修复 `contains` 崩溃并改进 C++ std 模块的 PCH +* [#7580](https://github.com/xmake-io/xmake/pull/7580): 修复 format 插件在头文件路径已是绝对路径时的处理 +* [#7581](https://github.com/xmake-io/xmake/pull/7581): 修复包加载函数中缺失的括号 +* [#7583](https://github.com/xmake-io/xmake/pull/7583): 修复 cmake 包的全局 flags 拆分 +* [#7599](https://github.com/xmake-io/xmake/pull/7599): 修复 OpenBSD 上的 gzip / tar 检测 +* [#7600](https://github.com/xmake-io/xmake/pull/7600): 修复构建缓存 memcache 的启用 +* [#7601](https://github.com/xmake-io/xmake/pull/7601): 修复 verilator 确保定义 `TRACE` +* [#7602](https://github.com/xmake-io/xmake/pull/7602): 修复包加载 memcache +* [#7603](https://github.com/xmake-io/xmake/pull/7603): 通过更新 tbox 修复 `rmdir` +* [#7604](https://github.com/xmake-io/xmake/pull/7604): 修复 elf 的 rpath 清理 +* [#7608](https://github.com/xmake-io/xmake/pull/7608): 修复拼写错误并格式化命令菜单 +* [#7611](https://github.com/xmake-io/xmake/pull/7611): 修复缓存环境变量处理([#7576](https://github.com/xmake-io/xmake/issues/7576)) +* [#7622](https://github.com/xmake-io/xmake/pull/7622): 修复 deb 打包的默认 maintainer +* [#7627](https://github.com/xmake-io/xmake/pull/7627): 修复 debuild 中的 PATH 处理 +* [#7631](https://github.com/xmake-io/xmake/pull/7631): 修复安装 deb 包时的 PATH 处理 +* [#7633](https://github.com/xmake-io/xmake/pull/7633): 修复 Meson 后端在 BSD 上的 pkg-config 路径 +* [#7640](https://github.com/xmake-io/xmake/pull/7640): 改进 emcc 检测,添加回退查找 +* [#7644](https://github.com/xmake-io/xmake/pull/7644): 修复路径转换中长路径的栈缓冲区溢出 +* [#7645](https://github.com/xmake-io/xmake/pull/7645): 修复删除只读目录 +* [#7659](https://github.com/xmake-io/xmake/pull/7659): 修复 Windows 上 emcc 的 `.exe` / `.bat` 检测 +* [#7661](https://github.com/xmake-io/xmake/pull/7661): 回退 clang 的静态 libc++ 链接 +* [#7668](https://github.com/xmake-io/xmake/pull/7668): 修复向 cmake 传递路径 +* [#7671](https://github.com/xmake-io/xmake/pull/7671): 修复 tbox 的一些 bug +* [#7674](https://github.com/xmake-io/xmake/pull/7674): 修复 macOS 上的 Mach host send-right 泄漏 +* [#7676](https://github.com/xmake-io/xmake/pull/7676): 修复 masm 的 embed / edit 级别符号 flag +* [#7679](https://github.com/xmake-io/xmake/pull/7679): 修复 msvc 在 C 模式下的 `set_pcheader` +* [#7684](https://github.com/xmake-io/xmake/pull/7684): 修复 `process.open` 中错误的 Lua 栈索引 +* [#7685](https://github.com/xmake-io/xmake/pull/7685): 修复引擎资源泄漏 +* [#7687](https://github.com/xmake-io/xmake/pull/7687): 修复 ninja 生成器未给 `win.sdk.resource` 源文件批次生成构建边的问题([#7682](https://github.com/xmake-io/xmake/issues/7682)) +* [#7692](https://github.com/xmake-io/xmake/pull/7692): 修复 `build.c++.modules.tryreuse` 的依赖顺序 +* 修复 scons 的 trybuild + ## v3.0.9 ### 新特性 diff --git a/core/src/cli/xmake.lua b/core/src/cli/xmake.lua index 7cd50cb2c..54b78806d 100644 --- a/core/src/cli/xmake.lua +++ b/core/src/cli/xmake.lua @@ -58,7 +58,8 @@ target("cli") add_installfiles("$(projectdir)/../NOTICE.md") add_installfiles("$(projectdir)/../xmake/(**.lua)") add_installfiles("$(projectdir)/../xmake/(scripts/**)") - add_installfiles("$(projectdir)/../xmake/(repository/templates/**)") + add_installfiles("$(projectdir)/../xmake/(templates/**)") + add_installfiles("$(projectdir)/../xmake/(repository/**)") add_installfiles("$(projectdir)/../scripts/xrepo.bat") add_installfiles("$(projectdir)/../scripts/xrepo.ps1") set_prefixdir("/", {bindir = "/"}) @@ -68,7 +69,8 @@ target("cli") else add_installfiles("$(projectdir)/../(xmake/**.lua)", {prefixdir = "share"}) add_installfiles("$(projectdir)/../(xmake/scripts/**)", {prefixdir = "share"}) - add_installfiles("$(projectdir)/../(xmake/repository/templates/**)", {prefixdir = "share"}) + add_installfiles("$(projectdir)/../(xmake/templates/**)", {prefixdir = "share"}) + add_installfiles("$(projectdir)/../(xmake/repository/**)", {prefixdir = "share"}) add_installfiles("$(projectdir)/../scripts/xrepo.sh", {prefixdir = "bin", filename = "xrepo"}) end diff --git a/core/src/cli/xmake.sh b/core/src/cli/xmake.sh index af4e8ba36..a7ef02601 100755 --- a/core/src/cli/xmake.sh +++ b/core/src/cli/xmake.sh @@ -32,7 +32,8 @@ target "cli" add_installfiles "${projectdir}/(xmake/scripts/virtualenvs/**)" "share" add_installfiles "${projectdir}/(xmake/scripts/conan/**)" "share" add_installfiles "${projectdir}/(xmake/scripts/module/**)" "share" - add_installfiles "${projectdir}/(xmake/repository/templates/**)" "share" + add_installfiles "${projectdir}/(xmake/templates/**)" "share" + add_installfiles "${projectdir}/(xmake/repository/**)" "share" add_installfiles "${projectdir}/scripts/xrepo.sh" "bin" "xrepo" # fix os.exec() call incorrect program from /mingw64/bin. e.g. python, .. diff --git a/core/src/tbox/tbox b/core/src/tbox/tbox -Subproject 870b2b9e4337694bb381d55338364c8b9711b82 +Subproject 3330978dce512b5c7104683383a40ab2b14be73 diff --git a/core/src/xmake/binutils/ar/extractlib.c b/core/src/xmake/binutils/ar/extractlib.c index d9629394a..830eb3275 100644 --- a/core/src/xmake/binutils/ar/extractlib.c +++ b/core/src/xmake/binutils/ar/extractlib.c @@ -212,7 +212,7 @@ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outpu ok = tb_false; } - tb_stream_clos(ostream); + tb_stream_close(ostream); tb_stream_exit(ostream); tb_check_break(ok); diff --git a/core/src/xmake/binutils/extractlib.c b/core/src/xmake/binutils/extractlib.c index fbfbacfef..735859ade 100644 --- a/core/src/xmake/binutils/extractlib.c +++ b/core/src/xmake/binutils/extractlib.c @@ -129,7 +129,7 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) { } while (0); if (istream) { - tb_stream_clos(istream); + tb_stream_close(istream); tb_stream_exit(istream); } diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c index b93b29bb0..b37817cc9 100644 --- a/core/src/xmake/engine.c +++ b/core/src/xmake/engine.c @@ -814,6 +814,10 @@ static tb_bool_t xm_engine_save_arguments(xm_engine_t *engine, tb_int_t argc, tb lua_rawseti(engine->lua, -2, (int)lua_objlen(engine->lua, -2) + 1); } +#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) + LocalFree(argvw); +#endif + // _ARGV = table_new lua_setglobal(engine->lua, "_ARGV"); return tb_true; @@ -1445,8 +1449,8 @@ static tb_bool_t xm_engine_extract_programfiles_impl(xm_engine_t *engine, if (tb_stream_open(stream)) { tb_stream_bwrit(stream, p, n); - tb_stream_exit(stream); } + tb_stream_exit(stream); p += n; } diff --git a/core/src/xmake/engine_pool.c b/core/src/xmake/engine_pool.c index 39bdb1339..b9df842eb 100644 --- a/core/src/xmake/engine_pool.c +++ b/core/src/xmake/engine_pool.c @@ -43,6 +43,18 @@ #define XM_ENGINE_POOL (TB_SINGLETON_TYPE_USER + 4) /* ////////////////////////////////////////////////////////////////////////////////////// + * globals + */ + +/* the engine pool lock + * + * the pool is a singleton shared by all worker threads, which may alloc/free engines + * concurrently (e.g. parallel batchcmds:lua/vlua jobs run in native threads), so we must + * protect the underlying list against data races, otherwise it will be corrupted and crash. + */ +static tb_spinlock_t g_engine_pool_lock = TB_SPINLOCK_INIT; + +/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_handle_t xm_engine_pool_instance_init(tb_cpointer_t *ppriv) { @@ -83,17 +95,22 @@ tb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool) { xm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool) { xm_engine_ref_t engine = tb_null; + tb_spinlock_enter(&g_engine_pool_lock); if (tb_single_list_size(engine_pool) > 0) { engine = (xm_engine_ref_t)tb_single_list_head(engine_pool); tb_single_list_remove_head(engine_pool); } + tb_spinlock_leave(&g_engine_pool_lock); return engine; } tb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine) { + tb_bool_t ok = tb_false; + tb_spinlock_enter(&g_engine_pool_lock); if (tb_single_list_size(engine_pool) < XM_ENGINE_POOL_MAXN) { tb_single_list_insert_tail(engine_pool, engine); - return tb_true; + ok = tb_true; } - return tb_false; + tb_spinlock_leave(&g_engine_pool_lock); + return ok; } diff --git a/core/src/xmake/io/file_close.c b/core/src/xmake/io/file_close.c index bb5cf1060..303f9f002 100644 --- a/core/src/xmake/io/file_close.c +++ b/core/src/xmake/io/file_close.c @@ -68,7 +68,7 @@ tb_int_t xm_io_file_close(lua_State *lua) { } // close file - tb_stream_clos(file->u.file_ref); + tb_stream_close(file->u.file_ref); file->u.file_ref = tb_null; // exit fstream diff --git a/core/src/xmake/io/file_write.c b/core/src/xmake/io/file_write.c index fdfd5afe7..5f860d641 100644 --- a/core/src/xmake/io/file_write.c +++ b/core/src/xmake/io/file_write.c @@ -110,7 +110,7 @@ static tb_void_t xm_io_file_write_std(xm_io_file_t *file, tb_byte_t const *data, tb_check_return(type != XM_IO_FILE_TYPE_STDIN); // write data to stdout/stderr - tb_stdfile_writ(file->u.std_ref, data, size); + tb_stdfile_write(file->u.std_ref, data, size); } /* ////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/xmake/os/cpuinfo.c b/core/src/xmake/os/cpuinfo.c index 47542a4b4..e931f7912 100644 --- a/core/src/xmake/os/cpuinfo.c +++ b/core/src/xmake/os/cpuinfo.c @@ -70,8 +70,9 @@ static tb_float_t xm_os_cpuinfo_usagerate() { processor_info_array_t cpuinfo; mach_msg_type_number_t cpuinfo_count; static tb_hong_t s_time = 0; + host_t host = mach_host_self(); if (tb_mclock() - s_time > 1000 && - host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, &cpuinfo, &cpuinfo_count) == + host_processor_info(host, PROCESSOR_CPU_LOAD_INFO, &cpu_count, &cpuinfo, &cpuinfo_count) == KERN_SUCCESS) { static processor_info_array_t s_cpuinfo_prev = tb_null; static mach_msg_type_number_t s_cpuinfo_count_prev = 0; @@ -100,6 +101,7 @@ static tb_float_t xm_os_cpuinfo_usagerate() { s_cpuinfo_prev = cpuinfo; s_cpuinfo_count_prev = cpuinfo_count; } + mach_port_deallocate(mach_task_self(), host); return cpu_count > 0 ? usagerate / cpu_count : 0; #elif defined(TB_CONFIG_OS_WINDOWS) // kernel include idle_time diff --git a/core/src/xmake/os/meminfo.c b/core/src/xmake/os/meminfo.c index 96db76f0d..0671d5311 100644 --- a/core/src/xmake/os/meminfo.c +++ b/core/src/xmake/os/meminfo.c @@ -61,7 +61,10 @@ static tb_bool_t xm_os_meminfo_stats(tb_int_t *ptotalsize, tb_int_t *pavailsize) #if defined(TB_CONFIG_OS_MACOSX) vm_statistics64_data_t vmstat; mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; - if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info_t)&vmstat, &count) == KERN_SUCCESS) { + host_t host = mach_host_self(); + kern_return_t result = host_statistics64(host, HOST_VM_INFO64, (host_info_t)&vmstat, &count); + mach_port_deallocate(mach_task_self(), host); + if (result == KERN_SUCCESS) { tb_int_t pagesize = (tb_int_t)tb_page_size(); tb_int64_t totalsize = (tb_int64_t)(vmstat.inactive_count + vmstat.free_count + vmstat.active_count + vmstat.wire_count diff --git a/core/src/xmake/process/open.c b/core/src/xmake/process/open.c index b6cf272b2..5ae958f8d 100644 --- a/core/src/xmake/process/open.c +++ b/core/src/xmake/process/open.c @@ -75,7 +75,7 @@ tb_int_t xm_process_open(lua_State *lua) { // get curdir lua_pushstring(lua, "curdir"); - lua_gettable(lua, 3); + lua_gettable(lua, 2); attr.curdir = lua_tostring(lua, -1); lua_pop(lua, 1); @@ -100,7 +100,7 @@ tb_int_t xm_process_open(lua_State *lua) { // get infile if (!inpath) { lua_pushstring(lua, "infile"); - lua_gettable(lua, 3); + lua_gettable(lua, 2); infile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } @@ -108,7 +108,7 @@ tb_int_t xm_process_open(lua_State *lua) { // get outfile if (!outpath) { lua_pushstring(lua, "outfile"); - lua_gettable(lua, 3); + lua_gettable(lua, 2); outfile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } @@ -116,7 +116,7 @@ tb_int_t xm_process_open(lua_State *lua) { // get errfile if (!errpath) { lua_pushstring(lua, "errfile"); - lua_gettable(lua, 3); + lua_gettable(lua, 2); errfile = (xm_io_file_t *)lua_touserdata(lua, -1); lua_pop(lua, 1); } @@ -124,7 +124,7 @@ tb_int_t xm_process_open(lua_State *lua) { // get inpipe if (!inpath && !infile) { lua_pushstring(lua, "inpipe"); - lua_gettable(lua, 3); + lua_gettable(lua, 2); inpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } @@ -132,7 +132,7 @@ tb_int_t xm_process_open(lua_State *lua) { // get outpipe if (!outpath && !outfile) { lua_pushstring(lua, "outpipe"); - lua_gettable(lua, 3); + lua_gettable(lua, 2); outpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } @@ -140,7 +140,7 @@ tb_int_t xm_process_open(lua_State *lua) { // get errpipe if (!errpath && !errfile) { lua_pushstring(lua, "errpipe"); - lua_gettable(lua, 3); + lua_gettable(lua, 2); errpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1); lua_pop(lua, 1); } diff --git a/core/src/xmake/semver/select.c b/core/src/xmake/semver/select.c index 283afb050..e95840eab 100644 --- a/core/src/xmake/semver/select.c +++ b/core/src/xmake/semver/select.c @@ -33,6 +33,69 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ +static tb_char_t const *xm_semver_skip_version_prefix(tb_char_t const *version_str, tb_size_t *version_len) { + if (*version_len && (version_str[0] == 'v' || version_str[0] == '=')) { + ++version_str; + --*version_len; + } + return version_str; +} +static tb_bool_t xm_semver_is_exact_version( + tb_char_t const *version_str, tb_size_t version_len, tb_bool_t *is_exact_with_build) { + *is_exact_with_build = tb_false; + version_str = xm_semver_skip_version_prefix(version_str, &version_len); + semver_t version = { 0 }; + if (!semvern(&version, version_str, version_len)) { + *is_exact_with_build = version.build.len > 0; + semver_dtor(&version); + return tb_true; + } + return tb_false; +} +static tb_long_t xm_semver_compare_build(semver_id_t const *left, semver_id_t const *right) { + while (left && right && left->len && right->len) { + if (left->numeric && right->numeric) { + if (left->num != right->num) { + return left->num > right->num ? 1 : -1; + } + } else { + tb_size_t size = left->len < right->len ? left->len : right->len; + tb_long_t result = tb_memcmp(left->raw, right->raw, size); + if (result) { + return result; + } + if (left->len != right->len) { + return left->len > right->len ? 1 : -1; + } + } + left = left->next; + right = right->next; + } + if (left && left->len) { + return 1; + } + if (right && right->len) { + return -1; + } + return 0; +} +static tb_long_t xm_semver_compare_with_build(semver_t const *left, semver_t const *right) { + tb_long_t result = semver_pcmp(left, right); + // xmake-repo orders build metadata as package revisions + return result ? result : xm_semver_compare_build(&left->build, &right->build); +} +static semver_t const *xm_semvers_find_newest(semvers_t const *versions) { + tb_assert_and_check_return_val(versions && versions->length, tb_null); + + semver_t const *newest = &versions->data[0]; + tb_size_t i = 0; + for (i = 1; i < versions->length; ++i) { + if (xm_semver_compare_with_build(&versions->data[i], newest) > 0) { + newest = &versions->data[i]; + } + } + return newest; +} static tb_bool_t xm_semver_select_from_versions_tags1( lua_State *lua, tb_int_t fromidx, semver_t *semver, semver_range_t const *range, semvers_t *matches) { // clear matches @@ -59,27 +122,24 @@ static tb_bool_t xm_semver_select_from_versions_tags1( // no matches? tb_check_return_val(matches->length, tb_false); - // sort matches - semvers_psort(matches); - // get the newest version - semver_t top = semvers_ppop(matches); + semver_t const *top = xm_semvers_find_newest(matches); lua_createtable(lua, 0, 2); // return results - lua_pushstring(lua, top.raw); + lua_pushstring(lua, top->raw); lua_setfield(lua, -2, "version"); lua_pushstring(lua, fromidx == 2 ? "version" : "tag"); lua_setfield(lua, -2, "source"); - // exit the popped semver - semver_dtor(&top); - return tb_true; } static tb_bool_t xm_semver_select_from_versions_tags2( - lua_State *lua, tb_int_t fromidx, semver_t *semver, tb_char_t const *version_str, tb_size_t version_len) { + lua_State *lua, tb_int_t fromidx, tb_char_t const *version_str, tb_size_t version_len, tb_bool_t is_exact) { + if (is_exact) { + version_str = xm_semver_skip_version_prefix(version_str, &version_len); + } lua_Integer i = 0; luaL_checktype(lua, fromidx, LUA_TTABLE); for (i = lua_objlen(lua, fromidx); i > 0; --i) { @@ -88,8 +148,14 @@ static tb_bool_t xm_semver_select_from_versions_tags2( tb_char_t const *source_str = luaL_checkstring(lua, -1); tb_size_t source_len = tb_strlen(source_str); + tb_size_t source_version_len = source_len; + tb_char_t const *source_version_str = source_str; + // ignore a leading v/= prefix when comparing exact versions + if (is_exact) { + source_version_str = xm_semver_skip_version_prefix(source_str, &source_version_len); + } lua_pop(lua, 1); - if (source_len == version_len && tb_strncmp(source_str, version_str, version_len) == 0) { + if (source_version_len == version_len && tb_strncmp(source_version_str, version_str, version_len) == 0) { lua_createtable(lua, 0, 2); lua_pushlstring(lua, source_str, source_len); lua_setfield(lua, -2, "version"); @@ -147,21 +213,17 @@ static tb_bool_t xm_semver_select_latest_from_versions_tags(lua_State *lua, } tb_check_return_val(matches->length, tb_false); - // sort matches - semvers_psort(matches); - // get the newest match - semver_t top = semvers_ppop(matches); + semver_t const *top = xm_semvers_find_newest(matches); lua_createtable(lua, 0, 2); // return results - lua_pushstring(lua, top.raw); + lua_pushstring(lua, top->raw); lua_setfield(lua, -2, "version"); lua_pushstring(lua, fromidx == 2 ? "version" : "tag"); lua_setfield(lua, -2, "source"); - semver_dtor(&top); return tb_true; } @@ -179,6 +241,8 @@ tb_int_t xm_semver_select(lua_State *lua) { // select version tb_bool_t ok = tb_false; tb_bool_t is_range = tb_false; + tb_bool_t is_exact = tb_false; + tb_bool_t is_exact_with_build = tb_false; tb_char_t const *range_str = tb_null; semver_t semver = { 0 }; semvers_t matches = { 0 }; @@ -193,27 +257,27 @@ tb_int_t xm_semver_select(lua_State *lua) { // parse the version range string is_range = semver_rangen(&range, range_str, range_len) == 0; - if (is_range) { - // attempt to select version from the versions list first - if (xm_semver_select_from_versions_tags1(lua, 2, &semver, &range, &matches)) { + is_exact = xm_semver_is_exact_version(range_str, range_len, &is_exact_with_build); + + // matching order: versions exact -> tags exact -> versions range -> tags range + if (is_exact || !is_range) { + if (xm_semver_select_from_versions_tags2(lua, 2, range_str, range_len, is_exact)) { ok = tb_true; break; } - - // attempt to select version from the tags list - if (xm_semver_select_from_versions_tags1(lua, 3, &semver, &range, &matches)) { + if (xm_semver_select_from_versions_tags2(lua, 3, range_str, range_len, is_exact)) { ok = tb_true; break; } - } else { - // attempt to select version from the versions list first - if (xm_semver_select_from_versions_tags2(lua, 2, &semver, range_str, range_len)) { + } + + // a build-qualified exact version identifies a specific package revision + if (is_range && !is_exact_with_build) { + if (xm_semver_select_from_versions_tags1(lua, 2, &semver, &range, &matches)) { ok = tb_true; break; } - - // attempt to select version from the tags list - if (xm_semver_select_from_versions_tags2(lua, 3, &semver, range_str, range_len)) { + if (xm_semver_select_from_versions_tags1(lua, 3, &semver, &range, &matches)) { ok = tb_true; break; } diff --git a/core/src/xmake/utf8/width.c b/core/src/xmake/utf8/width.c index 615572462..fb79ee198 100644 --- a/core/src/xmake/utf8/width.c +++ b/core/src/xmake/utf8/width.c @@ -33,7 +33,11 @@ * utf8.width(codepoint) */ tb_int_t xm_utf8_width(lua_State* lua) { - if (lua_isnumber(lua, 1)) { + /* we must not use lua_isnumber() here: it also accepts a numeric string, + * so utf8.width("9") would return the width of the code point 9 (a tab) + * instead of the width of the string "9" + */ + if (lua_type(lua, 1) == LUA_TNUMBER) { xm_utf8_int_t val = (xm_utf8_int_t)lua_tointeger(lua, 1); lua_pushinteger(lua, xm_utf8_charwidth(val)); } else { diff --git a/core/xmake.lua b/core/xmake.lua index 97d19c568..5536cbf98 100644 --- a/core/xmake.lua +++ b/core/xmake.lua @@ -1,7 +1,7 @@ set_project("xmake") set_xmakever("3.0.5") set_policy("build.progress_style", "multirow") -set_version("3.0.9", {build = "%Y%m%d"}) +set_version("3.1.1", {build = "%Y%m%d"}) -- set all warnings as errors set_warnings("all", "error") diff --git a/core/xmake.sh b/core/xmake.sh index 31c5f8aea..935a7158b 100755 --- a/core/xmake.sh +++ b/core/xmake.sh @@ -1,7 +1,7 @@ #!/bin/sh set_project "xmake" -set_version "3.0.9" "%Y%m%d" +set_version "3.1.1" "%Y%m%d" # set warning all set_warnings "all" diff --git a/scripts/get.ps1 b/scripts/get.ps1 index 99ad1edba..487675c21 100755 --- a/scripts/get.ps1 +++ b/scripts/get.ps1 @@ -11,7 +11,7 @@ param ( ) & { - $LastRelease = "v3.0.9" + $LastRelease = "v3.1.1" $ErrorActionPreference = 'Stop' function writeErrorTip($msg) { diff --git a/scripts/rpmbuild/xmake.spec b/scripts/rpmbuild/xmake.spec index df59e545a..fd4695904 100644 --- a/scripts/rpmbuild/xmake.spec +++ b/scripts/rpmbuild/xmake.spec @@ -3,7 +3,7 @@ %undefine __brp_mangle_shebangs Name: xmake -Version: 3.0.9 +Version: 3.1.1 Release: 1%{?dist} Summary: A cross-platform build utility based on Lua diff --git a/tests/actions/addon/custom-include/addon.lua b/tests/actions/addon/custom-include/addon.lua new file mode 100644 index 000000000..71d01b5c2 --- /dev/null +++ b/tests/actions/addon/custom-include/addon.lua @@ -0,0 +1,2 @@ +addon("custom-include") + set_description("the addon which provides a custom includes file") diff --git a/tests/actions/addon/custom-include/includes/check/xmake.lua b/tests/actions/addon/custom-include/includes/check/xmake.lua new file mode 100644 index 000000000..953f7ba73 --- /dev/null +++ b/tests/actions/addon/custom-include/includes/check/xmake.lua @@ -0,0 +1,4 @@ +option("myoption") + set_default(true) + set_description("The option of the custom-include addon.") +print("custom-include: includes check is loaded") diff --git a/tests/actions/addon/custom-module/addon.lua b/tests/actions/addon/custom-module/addon.lua new file mode 100644 index 000000000..604dbc645 --- /dev/null +++ b/tests/actions/addon/custom-module/addon.lua @@ -0,0 +1,2 @@ +addon("custom-module") + set_description("the addon which provides a custom module") diff --git a/tests/actions/addon/custom-module/modules/greeting.lua b/tests/actions/addon/custom-module/modules/greeting.lua new file mode 100644 index 000000000..843dddfc2 --- /dev/null +++ b/tests/actions/addon/custom-module/modules/greeting.lua @@ -0,0 +1,3 @@ +function main(name) + return "hello from custom-module: " .. name +end diff --git a/tests/actions/addon/custom-override/addon.lua b/tests/actions/addon/custom-override/addon.lua new file mode 100644 index 000000000..3540b51f5 --- /dev/null +++ b/tests/actions/addon/custom-override/addon.lua @@ -0,0 +1,2 @@ +addon("custom-override") + set_description("the addon which takes over a builtin plugin") diff --git a/tests/actions/addon/custom-override/plugins/format/main.lua b/tests/actions/addon/custom-override/plugins/format/main.lua new file mode 100644 index 000000000..92f9b73b8 --- /dev/null +++ b/tests/actions/addon/custom-override/plugins/format/main.lua @@ -0,0 +1,3 @@ +function main() + print("hello from custom-override") +end diff --git a/tests/actions/addon/custom-override/plugins/format/xmake.lua b/tests/actions/addon/custom-override/plugins/format/xmake.lua new file mode 100644 index 000000000..446e24db1 --- /dev/null +++ b/tests/actions/addon/custom-override/plugins/format/xmake.lua @@ -0,0 +1,6 @@ +-- @note `format` is a builtin plugin of xmake, we use it to test that an addon +-- is able to take over a builtin plugin +task("format") + set_category("plugin") + set_menu {usage = "xmake format", description = "Say hello instead of formatting.", options = {}} + on_run("main") diff --git a/tests/actions/addon/custom-package/addon.lua b/tests/actions/addon/custom-package/addon.lua new file mode 100644 index 000000000..56d8300f3 --- /dev/null +++ b/tests/actions/addon/custom-package/addon.lua @@ -0,0 +1,2 @@ +addon("custom-package") + set_description("the addon which provides a custom package") diff --git a/tests/actions/addon/custom-package/includes/packages/src/include/hello_utils.h b/tests/actions/addon/custom-package/includes/packages/src/include/hello_utils.h new file mode 100644 index 000000000..ca969acd2 --- /dev/null +++ b/tests/actions/addon/custom-package/includes/packages/src/include/hello_utils.h @@ -0,0 +1,6 @@ +#pragma once +#include <stdio.h> + +static inline void hello_utils_greeting(void) { + printf("hello from the custom package!\n"); +} diff --git a/tests/actions/addon/custom-package/includes/packages/xmake.lua b/tests/actions/addon/custom-package/includes/packages/xmake.lua new file mode 100644 index 000000000..5a02187fd --- /dev/null +++ b/tests/actions/addon/custom-package/includes/packages/xmake.lua @@ -0,0 +1,13 @@ +-- an addon can ship the package definitions, so that a project only needs +-- includes("@addon/custom-package/packages") and add_requires("hello-utils") +package("hello-utils") + set_kind("library", {headeronly = true}) + set_description("the custom package of the tests") + + -- the sources are shipped by this addon, so it can be installed offline + set_sourcedir(path.join(os.scriptdir(), "src")) + + on_install(function (package) + os.cp("include", package:installdir()) + end) +package_end() diff --git a/tests/actions/addon/custom-plugin/addon.lua b/tests/actions/addon/custom-plugin/addon.lua new file mode 100644 index 000000000..ba4515c78 --- /dev/null +++ b/tests/actions/addon/custom-plugin/addon.lua @@ -0,0 +1,2 @@ +addon("custom-plugin") + set_description("the addon which provides a custom plugin") diff --git a/tests/actions/addon/custom-plugin/plugins/hello_addon/main.lua b/tests/actions/addon/custom-plugin/plugins/hello_addon/main.lua new file mode 100644 index 000000000..0cf3a0386 --- /dev/null +++ b/tests/actions/addon/custom-plugin/plugins/hello_addon/main.lua @@ -0,0 +1,5 @@ +import("core.base.option") + +function main() + print("hello from custom-plugin: %s", option.get("name") or "world") +end diff --git a/tests/actions/addon/custom-plugin/plugins/hello_addon/xmake.lua b/tests/actions/addon/custom-plugin/plugins/hello_addon/xmake.lua new file mode 100644 index 000000000..7976a1d0e --- /dev/null +++ b/tests/actions/addon/custom-plugin/plugins/hello_addon/xmake.lua @@ -0,0 +1,5 @@ +task("hello_addon") + set_category("plugin") + set_menu {usage = "xmake hello_addon", description = "Say hello from the addon.", + options = {{'n', "name", "kv", nil, "Set the name."}}} + on_run("main") diff --git a/tests/actions/addon/custom-rule/addon.lua b/tests/actions/addon/custom-rule/addon.lua new file mode 100644 index 000000000..2e9b68ab5 --- /dev/null +++ b/tests/actions/addon/custom-rule/addon.lua @@ -0,0 +1,2 @@ +addon("custom-rule") + set_description("the addon which provides a custom rule") diff --git a/tests/actions/addon/custom-rule/modules/greeting.lua b/tests/actions/addon/custom-rule/modules/greeting.lua new file mode 100644 index 000000000..f247d21ca --- /dev/null +++ b/tests/actions/addon/custom-rule/modules/greeting.lua @@ -0,0 +1,3 @@ +function main(name) + return "hello from custom-rule: " .. name +end diff --git a/tests/actions/addon/custom-rule/rules/hello/xmake.lua b/tests/actions/addon/custom-rule/rules/hello/xmake.lua new file mode 100644 index 000000000..07638387d --- /dev/null +++ b/tests/actions/addon/custom-rule/rules/hello/xmake.lua @@ -0,0 +1,6 @@ +rule("hello") + on_load(function (target) + -- the addon code refers to its own resources with `@self` + import("@self.greeting") + print("custom-rule: %s", greeting(target:name())) + end) diff --git a/tests/actions/addon/custom-template/addon.lua b/tests/actions/addon/custom-template/addon.lua new file mode 100644 index 000000000..f01eda9c9 --- /dev/null +++ b/tests/actions/addon/custom-template/addon.lua @@ -0,0 +1,2 @@ +addon("custom-template") + set_description("the addon which provides a custom project template") diff --git a/tests/actions/addon/custom-template/templates/c/customaddon/hello/src/main.c b/tests/actions/addon/custom-template/templates/c/customaddon/hello/src/main.c new file mode 100644 index 000000000..115a2a792 --- /dev/null +++ b/tests/actions/addon/custom-template/templates/c/customaddon/hello/src/main.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int main(int argc, char** argv) { + printf("hello from the custom-template addon!\n"); + return 0; +} diff --git a/tests/actions/addon/custom-template/templates/c/customaddon/hello/xmake.lua b/tests/actions/addon/custom-template/templates/c/customaddon/hello/xmake.lua new file mode 100644 index 000000000..33c36ec7e --- /dev/null +++ b/tests/actions/addon/custom-template/templates/c/customaddon/hello/xmake.lua @@ -0,0 +1,5 @@ +add_rules("mode.debug", "mode.release") + +target("${TARGET_NAME}") + set_kind("binary") + add_files("src/*.c") diff --git a/tests/actions/addon/custom-toolchain/addon.lua b/tests/actions/addon/custom-toolchain/addon.lua new file mode 100644 index 000000000..8537b3272 --- /dev/null +++ b/tests/actions/addon/custom-toolchain/addon.lua @@ -0,0 +1,6 @@ +addon("custom-toolchain") + set_description("the addon which provides a custom toolchain") + set_sourcedir("src") + -- the tool modules are imported with their plain names by the internal calls, + -- e.g. find_tool("mycl6x"), import("core.tools.mycl6x") + add_globalmodules("core.tools.mycl6x", "detect.tools.find_mycl6x") diff --git a/tests/actions/addon/custom-toolchain/src/modules/core/tools/mycl6x.lua b/tests/actions/addon/custom-toolchain/src/modules/core/tools/mycl6x.lua new file mode 100644 index 000000000..972242c98 --- /dev/null +++ b/tests/actions/addon/custom-toolchain/src/modules/core/tools/mycl6x.lua @@ -0,0 +1,12 @@ +-- the tool module of the my-c6000 toolchain +-- +-- @note our compiler behaves like gcc, it's just a wrapper of the host one, so we only +-- inherit it here, a real one implements the tool interfaces itself, e.g. `init`, +-- `nf_define`, `compargv`, `link`, @see tests/apis/custom_toolchain +-- +inherit("core.tools.gcc") + +-- init it +function init(self) + self:set("cxflags", "-DMY_C6000_TOOL") +end diff --git a/tests/actions/addon/custom-toolchain/src/modules/detect/tools/find_mycl6x.lua b/tests/actions/addon/custom-toolchain/src/modules/detect/tools/find_mycl6x.lua new file mode 100644 index 000000000..c0ed37914 --- /dev/null +++ b/tests/actions/addon/custom-toolchain/src/modules/detect/tools/find_mycl6x.lua @@ -0,0 +1,15 @@ +import("lib.detect.find_program") + +-- find the compiler of the my-c6000 toolchain +-- +-- @note it's just the host compiler, we only need a real program to build with, +-- the point of this test is that this finder itself comes from the addon +-- +function main(opt) + for _, name in ipairs({"gcc", "clang", "cc"}) do + local program = find_program(name, opt) + if program then + return program + end + end +end diff --git a/tests/actions/addon/custom-toolchain/src/toolchains/my-c6000/xmake.lua b/tests/actions/addon/custom-toolchain/src/toolchains/my-c6000/xmake.lua new file mode 100644 index 000000000..9b023bac7 --- /dev/null +++ b/tests/actions/addon/custom-toolchain/src/toolchains/my-c6000/xmake.lua @@ -0,0 +1,19 @@ +-- a custom toolchain distributed as an addon +-- +-- @see tests/apis/custom_toolchain for the same toolchain maintained inside a project, +-- distributing it as an addon is the recommended way +-- +toolchain("my-c6000") + set_kind("standalone") + set_description("the custom toolchain of the tests") + + set_toolset("cc", "mycl6x") + set_toolset("ld", "mycl6x") + + on_check(function (toolchain) + return import("lib.detect.find_tool")("mycl6x") + end) + + on_load(function (toolchain) + toolchain:add("cxflags", "-DMY_C6000") + end) diff --git a/tests/actions/addon/projects/autofetch-badname/xmake.lua b/tests/actions/addon/projects/autofetch-badname/xmake.lua new file mode 100644 index 000000000..ffbf6cbe4 --- /dev/null +++ b/tests/actions/addon/projects/autofetch-badname/xmake.lua @@ -0,0 +1,5 @@ +-- the `addon` name is reserved for the addon references +add_addons("addon") + +target("test") + set_kind("phony") diff --git a/tests/actions/addon/projects/autofetch-build/src/main.c b/tests/actions/addon/projects/autofetch-build/src/main.c new file mode 100644 index 000000000..43509bfeb --- /dev/null +++ b/tests/actions/addon/projects/autofetch-build/src/main.c @@ -0,0 +1,14 @@ +// the addons must provide the option and the toolchain of this project +#ifndef MYOPTION +# error the option of the custom-include addon is not found! +#endif +#ifndef MY_C6000 +# error the toolchain of the custom-toolchain addon is not used! +#endif +#ifndef MY_C6000_TOOL +# error the tool module of the custom-toolchain addon is not used! +#endif + +int main(int argc, char** argv) { + return 0; +} diff --git a/tests/actions/addon/projects/autofetch-build/xmake.lua b/tests/actions/addon/projects/autofetch-build/xmake.lua new file mode 100644 index 000000000..862ddf676 --- /dev/null +++ b/tests/actions/addon/projects/autofetch-build/xmake.lua @@ -0,0 +1,14 @@ +-- the addons which this project needs, they are installed automatically +add_addons("custom-include", "custom-rule", "custom-toolchain") + +-- the option comes from the includes file of an addon +includes("@addon/custom-include/check") + +target("hello") + set_kind("binary") + add_files("src/main.c") + add_rules("@addon/custom-rule/hello") + set_toolchains("@addon/custom-toolchain/my-c6000") + if has_config("myoption") then + add_defines("MYOPTION") + end diff --git a/tests/actions/addon/projects/autofetch-lockmiss/xmake-addons.lock b/tests/actions/addon/projects/autofetch-lockmiss/xmake-addons.lock new file mode 100644 index 000000000..750a8e609 --- /dev/null +++ b/tests/actions/addon/projects/autofetch-lockmiss/xmake-addons.lock @@ -0,0 +1,9 @@ +{ + __meta__ = { + version = "1.0" + }, + -- this version is not installed, we only install `latest` from the local directory + ["custom-include"] = { + version = "v9.9.9" + } +} diff --git a/tests/actions/addon/projects/autofetch-lockmiss/xmake.lua b/tests/actions/addon/projects/autofetch-lockmiss/xmake.lua new file mode 100644 index 000000000..a96a4e713 --- /dev/null +++ b/tests/actions/addon/projects/autofetch-lockmiss/xmake.lua @@ -0,0 +1,4 @@ +add_addons("custom-include") + +target("test") + set_kind("phony") diff --git a/tests/actions/addon/projects/autofetch/xmake.lua b/tests/actions/addon/projects/autofetch/xmake.lua new file mode 100644 index 000000000..75c909904 --- /dev/null +++ b/tests/actions/addon/projects/autofetch/xmake.lua @@ -0,0 +1,8 @@ +-- the addons which this project needs, they are installed automatically +add_addons("custom-include") + +-- the addon is installed automatically, so we can use its includes file here +includes("@addon/custom-include/check") + +target("test") + set_kind("phony") diff --git a/tests/actions/addon/projects/custom-package/src/main.c b/tests/actions/addon/projects/custom-package/src/main.c new file mode 100644 index 000000000..12208c880 --- /dev/null +++ b/tests/actions/addon/projects/custom-package/src/main.c @@ -0,0 +1,6 @@ +#include <hello_utils.h> + +int main(int argc, char** argv) { + hello_utils_greeting(); + return 0; +} diff --git a/tests/actions/addon/projects/custom-package/xmake.lua b/tests/actions/addon/projects/custom-package/xmake.lua new file mode 100644 index 000000000..1c967020d --- /dev/null +++ b/tests/actions/addon/projects/custom-package/xmake.lua @@ -0,0 +1,9 @@ +-- the package definitions come from the addon +includes("@addon/custom-package/packages") + +add_requires("hello-utils") + +target("test") + set_kind("binary") + add_files("src/main.c") + add_packages("hello-utils") diff --git a/tests/actions/addon/test.lua b/tests/actions/addon/test.lua new file mode 100644 index 000000000..fcc5c2efc --- /dev/null +++ b/tests/actions/addon/test.lua @@ -0,0 +1,507 @@ +import("core.base.global") +import("lib.detect.find_program") + +-- the addon fixtures, each of them provides one kind of payload only +-- +-- @note they are independent from each other, @see tests/actions/addon/custom-* + +function _addondir(name) + return path.join(os.scriptdir(), name) +end + +function _remove(name) + try { function () os.runv("xmake", {"addon", "--remove", "--force", name}) end } +end + +-- install the given addon fixture from its local directory +function _install(name) + _remove(name) + os.runv("xmake", {"addon", "--install", _addondir(name)}) +end + +-- run the given function with the addons installed, we always remove them again +function _with_addons(names, func) + for _, name in ipairs(names) do + _install(name) + end + try + { + func, + finally + { + -- @note try() swallows the errors if we do not re-raise them here + function (ok, errors) + for _, name in ipairs(names) do + _remove(name) + end + if not ok then + raise(errors) + end + end + } + } +end + +-- create a temporary repository which indexes the given addon fixtures, and register it +-- +-- @note the recipes only point at the fixtures with `set_sourcedir`, we need not generate any payload +function _with_repo(recipes, func) + + -- @note installing from a repository goes through the package manager, and it always + -- needs git, which cannot be installed on the hosts without a package manager, + -- e.g. dragonflybsd + if not find_program("git") then + print("git not found, we skip the repository tests!") + return + end + + local suffix = path.filename(os.tmpfile()):gsub("[^%w]", "") + local reponame = "addon-test-repo-" .. suffix + local repodir = os.tmpfile() .. ".addon-repo" + for name, body in pairs(recipes) do + io.writefile(path.join(repodir, "addons", name:sub(1, 1), name, "xmake.lua"), + ("package(%q)\n set_kind(\"addon\")\n set_description(\"the addon fixture of the tests\")\n %s\n"):format(name, body)) + end + + -- register the repository and clear the quick search cache, it will be rebuilt on the next search + local cachefile = path.join(global.cachedir(), "repository") + local cache = os.isfile(cachefile) and io.load(cachefile) or {} + cache.repositories = cache.repositories or {} + + -- a killed test run may leave its temporary repository registered, and a dangling + -- repository breaks every following xrepo command, so we drop them here + for name, dirs in pairs(cache.repositories) do + if name:startswith("addon-test-repo-") and not os.isdir(dirs[1]) then + cache.repositories[name] = nil + end + end + cache.repositories[reponame] = {repodir} + io.save(cachefile, cache) + os.tryrm(path.join(global.cachedir(), "quick_search")) + + try + { + function () + func(reponame) + end, + finally + { + -- @note try() swallows the errors if we do not re-raise them here + function (ok, errors) + for name, _ in pairs(recipes) do + _remove(name) + end + local cache = os.isfile(cachefile) and io.load(cachefile) or {} + if cache.repositories then + cache.repositories[reponame] = nil + end + io.save(cachefile, cache) + os.tryrm(path.join(global.cachedir(), "quick_search")) + os.tryrm(repodir) + if not ok then + raise(errors) + end + end + } + } +end + +-- run the given command in a temporary project and return its output +function _run_project(content, argv, opt) + opt = opt or {} + local projectdir = os.tmpfile() .. ".addon-project" + os.tryrm(projectdir) + io.writefile(path.join(projectdir, "xmake.lua"), content) + for file, filecontent in pairs(opt.files or {}) do + io.writefile(path.join(projectdir, file), filecontent) + end + local oldir = os.cd(projectdir) + local out, errors + try + { + function () out = os.iorunv("xmake", argv) end, + catch { function (e) errors = e end }, + finally + { + function () + os.cd(oldir) + os.tryrm(projectdir) + end + } + } + if errors then + raise(errors) + end + return out +end + +function _config_project(content) + return _run_project(content, {"config", "-y"}) +end + +-- copy the given fixture project to a temporary directory and run the given function in it +-- +-- @note we cannot run them in place, they would generate the lock and the build files, +-- @see tests/actions/addon/projects +-- +function _with_project(name, func) + local projectdir = os.tmpfile() .. ".addon-project" + os.tryrm(projectdir) + os.mkdir(projectdir) + os.cp(path.join(os.scriptdir(), "projects", name, "*"), projectdir) + local oldir = os.cd(projectdir) + try + { + function () + func(projectdir) + end, + finally + { + -- @note try() swallows the errors if we do not re-raise them here + function (ok, errors) + os.cd(oldir) + os.tryrm(projectdir) + if not ok then + raise(errors) + end + end + } + } +end + +-- only the payloads should be installed, our own files should not +function test_install(t) + _with_addons({"custom-toolchain"}, function () + + -- it has the `src` layout, e.g. set_sourcedir("src") + local installdir = path.join(global.directory(), "addons", "custom-toolchain", "latest") + t:require(os.isdir(path.join(installdir, "toolchains"))) + t:require(os.isdir(path.join(installdir, "modules"))) + for _, ourfile in ipairs({"src", "addon.lua"}) do + t:require_not(os.exists(path.join(installdir, ourfile))) + end + + -- the addon describes itself, we should get its description from the manifest + t:require(os.iorunv("xmake", {"addon", "--list"}):find("the addon which provides a custom toolchain", 1, true)) + end) +end + +-- an addon can provide a plugin, e.g. xmake hello_addon +function test_plugin(t) + _with_addons({"custom-plugin"}, function () + t:require(os.iorunv("xmake", {"hello_addon", "-n", "xmake"}):find("hello from custom-plugin: xmake", 1, true)) + end) + + -- it should not be runnable after removing it + t:require_not(try { function () os.runv("xmake", {"hello_addon"}); return true end }) +end + +-- an addon can provide a rule, e.g. add_rules("@addon/custom-rule/hello") +function test_rule(t) + local projectfile = [[ +target("test") + set_kind("phony") + add_rules("@addon/custom-rule/hello") +]] + _with_addons({"custom-rule"}, function () + -- the rule imports a module of its own addon with `@self` + t:require(_config_project(projectfile):find("custom-rule: hello from custom-rule: test", 1, true)) + end) + + -- it should fail if the addon which provides it is not installed + t:require_not(try { function () _config_project(projectfile); return true end }) +end + +-- an addon can provide a module, e.g. import("@addon.custom-module.greeting") +function test_module(t) + _with_addons({"custom-module"}, function () + local script = "import(\"@addon.custom-module.greeting\"); print(greeting(\"xmake\"))" + t:require(os.iorunv("xmake", {"lua", "-c", script}):find("hello from custom-module: xmake", 1, true)) + + -- the addon modules are namespaced, they cannot be imported with their plain names + t:require_not(try { function () os.runv("xmake", {"lua", "-c", "import(\"greeting\")"}); return true end }) + end) +end + +-- an addon can provide an includes file, e.g. includes("@addon/custom-include/check") +function test_include(t) + _with_addons({"custom-include"}, function () + local out = _config_project([[ +includes("@addon/custom-include/check") +target("test") + set_kind("phony") +]]) + t:require(out:find("custom-include: includes check is loaded", 1, true)) + end) +end + +-- an addon can provide a project template, e.g. xmake create -t customaddon.hello +function test_template(t) + _with_addons({"custom-template"}, function () + t:require(os.iorunv("xmake", {"create", "--list", "-l", "c"}):find("customaddon.hello", 1, true)) + + local projectdir = os.tmpfile() .. ".addon-project" + os.tryrm(projectdir) + os.runv("xmake", {"create", "-l", "c", "-t", "customaddon.hello", "-P", projectdir}) + t:require(os.isfile(path.join(projectdir, "src", "main.c"))) + os.tryrm(projectdir) + end) +end + +-- an addon can ship the package definitions in its includes file, so that a project +-- only needs `add_requires`, @see tests/actions/addon/custom-package +function test_include_packages(t) + + -- @note we need a compiler here, the project links against the package + if not (find_program("gcc") or find_program("clang") or find_program("cc")) then + return + end + _with_addons({"custom-package"}, function () + _with_project("custom-package", function () + t:require(os.iorunv("xmake", {"build", "-y"}):find("build ok", 1, true)) + t:require(os.iorunv("xmake", {"run"}):find("hello from the custom package", 1, true)) + end) + end) +end + +-- an addon can provide a toolchain and its tool modules +-- +-- @see tests/apis/custom_toolchain for the same toolchain maintained inside a project +function test_toolchain(t) + _with_addons({"custom-toolchain"}, function () + + -- the toolchain can be loaded with the addon name + local script = "import(\"core.tool.toolchain\"); print(toolchain.load(\"@addon/custom-toolchain/my-c6000\"):get(\"description\"))" + t:require(os.iorunv("xmake", {"lua", "-c", script}):find("the custom toolchain of the tests", 1, true)) + + -- its tool modules are exported by the manifest, so the internal calls can import them + -- with their plain names, e.g. add_globalmodules("core.tools.mycl6x") + -- + -- @note there is no builtin `mycl6x`, so they can only come from this addon + local script2 = "import(\"core.tools.mycl6x\"); assert(mycl6x.compargv, \"invalid tool module!\"); " .. + "import(\"lib.detect.find_tool\"); assert(find_tool(\"mycl6x\"), \"mycl6x not found!\")" + os.runv("xmake", {"lua", "-c", script2}) + + -- and a project can build with it, the flags of the toolchain and of its tool module + -- are both checked by the source file + -- + -- @note its compiler is just the host one, so we can only build with it if there is one + if find_program("gcc") or find_program("clang") or find_program("cc") then + _run_project([[ +target("test") + set_kind("binary") + set_toolchains("@addon/custom-toolchain/my-c6000") + add_files("src/main.c") +]], {"build", "-y"}, {files = {["src/main.c"] = [[ +#ifndef MY_C6000 +# error the flags of the addon toolchain are not used! +#endif +#ifndef MY_C6000_TOOL +# error the flags of its tool module are not used! +#endif +int main(int argc, char** argv) { return 0; } +]]}}) + end + end) +end + +-- the addons which a project declares with `add_addons` are installed automatically +-- +-- @note they must be installed before loading the project, it may use their includes files +function test_autofetch(t) + local recipes = {["custom-include"] = ("set_sourcedir(%q)"):format(_addondir("custom-include"))} + _with_repo(recipes, function () + _remove("custom-include") + _with_project("autofetch", function (projectdir) + + -- it should be installed when loading the project, so that its includes file can be found, + -- and we should tell the user why we install something, it may need to confirm and download + local output = os.iorunv("xmake", {"config", "-y"}) + t:require(output:find("custom-include: includes check is loaded", 1, true)) + t:require(output:find("this project needs the addons", 1, true)) + + -- and it should be locked + local lockfile = path.join(projectdir, "xmake-addons.lock") + t:require(os.isfile(lockfile)) + t:require(io.load(lockfile)["custom-include"] ~= nil) + + -- we should not install it again + t:require_not(os.iorunv("xmake", {"config", "-y"}):find("install custom-include", 1, true)) + end) + end) +end + +-- every command builds the option menu, which merges the project tasks in a best-effort way, +-- so the commands which need not the project should never install its addons +function test_autofetch_skipped_for_option_menu(t) + local recipes = {["custom-include"] = ("set_sourcedir(%q)"):format(_addondir("custom-include"))} + _with_repo(recipes, function () + _remove("custom-include") + _with_project("autofetch", function (projectdir) + os.runv("xmake", {"addon", "--list"}) + os.runv("xmake", {"lua", "-c", "print(\"hello\")"}) + t:require_not(os.isfile(path.join(projectdir, "xmake-addons.lock"))) + end) + end) +end + +-- a complete project which declares its addons with `add_addons` and builds with them, +-- @see tests/actions/addon/projects/autofetch-build +function test_autofetch_build(t) + + -- @note the compiler of the custom toolchain is just the host one, + -- so we can only build it if there is one + if not (find_program("gcc") or find_program("clang") or find_program("cc")) then + return + end + + local names = {"custom-include", "custom-rule", "custom-toolchain"} + local recipes = {} + for _, name in ipairs(names) do + recipes[name] = ("set_sourcedir(%q)"):format(_addondir(name)) + end + _with_repo(recipes, function () + for _, name in ipairs(names) do + _remove(name) + end + _with_project("autofetch-build", function (projectdir) + + -- all of them should be installed when loading the project, and it should build + -- with their includes file, rule and toolchain, @see src/main.c + local output = os.iorunv("xmake", {"build", "-y"}) + t:require(output:find("custom-include: includes check is loaded", 1, true)) + t:require(output:find("custom-rule: hello from custom-rule: hello", 1, true)) + t:require(output:find("build ok", 1, true)) + + -- and all of them should be locked + local lockinfo = io.load(path.join(projectdir, "xmake-addons.lock")) + for _, name in ipairs(names) do + t:require(lockinfo[name] ~= nil) + end + end) + end) +end + +-- a locked version which is not installed must not hide the addon +-- +-- @note the auto-fetch installs the locked version, but the commands which do not load +-- the project content only pin it, e.g. `xmake lua`, @see project._pin_addons() +-- +function test_autofetch_lock_missing_version(t) + _with_addons({"custom-include"}, function () + _with_project("autofetch-lockmiss", function () + local script = "import(\"core.package.addon\"); print(addon.addons()[\"custom-include\"] ~= nil)" + t:require(os.iorunv("xmake", {"lua", "-c", script}):find("true", 1, true)) + end) + end) +end + +-- the declared addons are checked, e.g. the reserved names +function test_autofetch_invalid(t) + _with_project("autofetch-badname", function () + t:require_not(try { function () os.runv("xmake", {"config", "-y"}); return true end }) + end) +end + +-- the addons can be installed from a repository, by plain name and by repo@name +function test_install_from_repo(t) + local recipes = {["custom-plugin"] = ("set_sourcedir(%q)"):format(_addondir("custom-plugin")), + ["custom-module"] = ("set_sourcedir(%q)"):format(_addondir("custom-module"))} + _with_repo(recipes, function (reponame) + os.runv("xmake", {"addon", "--install", "-y", "custom-plugin"}) + t:require(os.iorunv("xmake", {"hello_addon"}):find("hello from custom-plugin", 1, true)) + + os.runv("xmake", {"addon", "--remove", "custom-plugin"}) + os.runv("xmake", {"addon", "--install", "-y", reponame .. "@custom-plugin"}) + t:require(os.iorunv("xmake", {"hello_addon"}):find("hello from custom-plugin", 1, true)) + + -- it should be searchable, and the addons should not be found by the package search + -- + -- @note we cannot run the `xrepo` program here, it may not be in the PATH, e.g. on the ci, + -- and `xrepo search` is just a wrapper of it + -- + t:require(os.iorunv("xmake", {"addon", "--search", "custom-plugin"}):find("custom-plugin", 1, true)) + t:require_not(os.iorunv("xmake", {"lua", "private.xrepo", "search", "custom-plugin"}):find("custom-plugin", 1, true)) + + -- and several of them can be installed in one shot, they are resolved and installed together + os.runv("xmake", {"addon", "--remove", "--force", "custom-plugin"}) + os.runv("xmake", {"addon", "--install", "-y", "custom-plugin", reponame .. "@custom-module"}) + t:require(os.iorunv("xmake", {"hello_addon"}):find("hello from custom-plugin", 1, true)) + t:require(os.iorunv("xmake", {"lua", "-c", "import(\"@addon.custom-module.greeting\"); print(greeting(\"xmake\"))"}) + :find("hello from custom-module: xmake", 1, true)) + end) +end + +-- an addon can depend on the other addons, they are installed and activated together +function test_addon_deps(t) + local recipes = { + ["custom-module"] = ("set_sourcedir(%q)"):format(_addondir("custom-module")), + ["custom-plugin"] = ("set_sourcedir(%q)\n add_deps(\"custom-module\", {kind = \"addon\"})"):format(_addondir("custom-plugin")) + } + _with_repo(recipes, function () + os.runv("xmake", {"addon", "--install", "-y", "custom-plugin"}) + local out = os.iorunv("xmake", {"addon", "--list"}) + t:require(out:find("custom-plugin", 1, true)) + t:require(out:find("custom-module", 1, true)) + + -- we cannot remove the dependency, it's depended on by the other addon + t:require_not(try { function () os.runv("xmake", {"addon", "--remove", "custom-module"}); return true end }) + end) +end + +-- the plugins and the templates are not namespaced, the conflicts should be rejected when installing +function test_install_conflicts(t) + _with_addons({"custom-plugin"}, function () + + -- this addon provides the same plugin name + local clonedir = os.tmpfile() .. ".addon-clone" + os.tryrm(clonedir) + io.writefile(path.join(clonedir, "addon.lua"), "addon(\"custom-plugin-clone\")\n") + io.writefile(path.join(clonedir, "plugins", "hello_addon", "xmake.lua"), + "task(\"hello_addon\")\n set_category(\"plugin\")\n set_menu {}\n on_run(function () end)\n") + t:require_not(try { function () os.runv("xmake", {"addon", "--install", "-y", clonedir}); return true end }) + os.tryrm(clonedir) + + -- and the other commands should still work + t:require(os.iorunv("xmake", {"hello_addon"}):find("hello from custom-plugin", 1, true)) + end) +end + +-- an addon is able to take over a builtin plugin, so we can move a deprecated builtin +-- plugin to an addon, e.g. `xmake format` +function test_install_override(t) + + -- the builtin plugin is used if we do not install the addon + t:require_not(os.iorunv("xmake", {"format", "--help"}):find("Say hello instead of formatting", 1, true)) + + _with_addons({"custom-override"}, function () + local out = os.iorunv("xmake", {"format"}) + t:require(out:find("hello from custom-override", 1, true)) + + -- and it should not be reported as a conflict + t:require_not(out:find("conflicts", 1, true)) + t:require(os.iorunv("xmake", {"format", "--help"}):find("Say hello instead of formatting", 1, true)) + end) + + -- the builtin plugin is used again after removing the addon + t:require_not(os.iorunv("xmake", {"format", "--help"}):find("Say hello instead of formatting", 1, true)) +end + +-- the invalid installs should fail, and the `addon` name is reserved for the addon references +function test_invalid(t) + t:require_not(try { function () os.runv("xmake", {"addon", "--install", "-y", "addon-test-missing"}); return true end }) + t:require_not(try { function () os.runv("xmake", {"addon", "--install", "-y", "somerepo@.."}); return true end }) + + -- the addon name in its manifest must match the package name which distributes it + local recipes = {["custom-plugin-badname"] = ("set_sourcedir(%q)"):format(_addondir("custom-plugin"))} + _with_repo(recipes, function () + t:require_not(try { function () os.runv("xmake", {"addon", "--install", "-y", "custom-plugin-badname"}); return true end }) + end) + + -- the `addon` name is reserved + t:require_not(try { function () _config_project([[ +add_requires("addon") +target("test") + set_kind("phony") +]]); return true end }) +end diff --git a/tests/modules/project_depend/test.lua b/tests/modules/project_depend/test.lua new file mode 100644 index 000000000..2df79ba16 --- /dev/null +++ b/tests/modules/project_depend/test.lua @@ -0,0 +1,19 @@ +import("core.project.depend") + +function test_nested_values_append(t) + local dependinfo = {values = {{"clang", "-m64"}}} + local changed = depend.is_changed(dependinfo, {values = {{"clang", "-m64", "-DFEATURE_ON"}}}) + t:require(changed) +end + +function test_nested_values_remove(t) + local dependinfo = {values = {{"clang", "-m64", "-DFEATURE_ON"}}} + local changed = depend.is_changed(dependinfo, {values = {{"clang", "-m64"}}}) + t:require(changed) +end + +function test_nested_values_unchanged(t) + local dependinfo = {values = {{"clang", "-m64", "-DFEATURE_ON"}}} + local changed = depend.is_changed(dependinfo, {values = {{"clang", "-m64", "-DFEATURE_ON"}}}) + t:require_not(changed) +end diff --git a/tests/modules/semver/test.lua b/tests/modules/semver/test.lua index 1ab6dc8aa..57d213f4a 100755 --- a/tests/modules/semver/test.lua +++ b/tests/modules/semver/test.lua @@ -7,6 +7,12 @@ function _check_semver_select(t, results, required_ver, versions, tags, branches t:are_equal(source, results[2]) end +function _check_semver_select_failed(t, required_ver, versions, tags, branches) + t:will_raise(function() + semver.select(required_ver, versions or {}, tags or {}, branches or {}) + end, "unable to select version") +end + -- test select version function test_semver_select(t) @@ -18,15 +24,101 @@ function test_semver_select(t) , "^1.5.0" ,{"1.4.0", "1.5.0", "1.5.1"}) + _check_semver_select(t, {"3.53.0+200", "version"} + , "3.53.0+200" + , {"3.53.0+0", "3.53.0+100", "3.53.0+200"}) + + _check_semver_select_failed(t, "3.53.0+999", {"3.53.0+100"}) + + _check_semver_select(t, {"3.53.0+200", "version"} + , "3.53.0" + , {"3.53.0+0", "3.53.0+100", "3.53.0+200"}) + + _check_semver_select(t, {"3.53.0+200", "version"} + , "3.53.0" + , {"3.53.0+200", "3.53.0+100", "3.53.0+0"}) + + _check_semver_select(t, {"3.53.0+beta", "version"} + , "3.53.0" + , {"3.53.0+alpha", "3.53.0+beta"}) + + _check_semver_select(t, {"3.53.0+beta", "version"} + , "3.53.0" + , {"3.53.0+beta", "3.53.0+alpha"}) + + _check_semver_select(t, {"1.2.3", "version"} + , "1.2.3" + , {"1.2.3+1", "1.2.3"}) + + _check_semver_select(t, {"1.2.3", "version"} + , "=1.2.3" + , {"1.2.3+7", "1.2.3"}) + + _check_semver_select(t, {"1.2.9", "version"} + , "1.2" + , {"1.2", "1.2.9"}) + + _check_semver_select(t, {"1.9.0", "version"} + , "^1.2.3" + , {"^1.2.3", "1.2.3", "1.9.0"}) + + _check_semver_select(t, {"1.2.3", "tag"} + , "1.2.3" + , {"v1.2.3+7"} + , {"1.2.3"}) + + _check_semver_select(t, {"v1.2.3+7", "version"} + , "1.2.3+7" + , {"v1.2.3+8", "v1.2.3+7"}) + + _check_semver_select(t, {"1.2.3+7", "version"} + , "v1.2.3+7" + , {"1.2.3+8", "1.2.3+7"}) + + _check_semver_select(t, {"3.53.0+200", "tag"} + , "3.53.0+200" + , nil + , {"3.53.0+0", "3.53.0+200"}) + + _check_semver_select_failed(t, "3.53.0+999", nil, {"3.53.0+100"}) + + _check_semver_select(t, {"v1.2.3+7", "tag"} + , "=1.2.3+7" + , nil + , {"v1.2.3+7", "v1.2.3+8"}) + + _check_semver_select(t, {"v1.2.3+7", "tag"} + , "1.2.3+7" + , {"1.2.3+8"} + , {"v1.2.3+7"}) + _check_semver_select(t, {"master", "branch"} , "master" , {"1.4.0", "1.5.0", "1.5.1"} , {"v1.2.0", "v1.6.0"} , {"master", "dev"}) + _check_semver_select(t, {"next", "branch"} + , "next" + , nil + , {"vnext"} + , {"next"}) + _check_semver_select(t, {"1.5.1", "version"} , "latest" , {"1.4.0", "1.5.0", "1.5.1"}) + + _check_semver_select(t, {"1.0.0+10", "version"} + , "latest" + , {"1.0.0+9", "1.0.0+10"}) + + _check_semver_select(t, {"1.0.0+rev.10", "version"} + , "latest" + , {"1.0.0+rev.9", "1.0.0+rev.10"}) + + _check_semver_select(t, {"3.53.0+200", "version"} + , "latest" + , {"3.53.0+0", "3.53.0+200", "3.53.0+100"}) end -- select version diff --git a/tests/projects/c++/modules/stdmodules_deps_ordering/src/foo.cpp b/tests/projects/c++/modules/stdmodules_deps_ordering/src/foo.cpp new file mode 100644 index 000000000..5b9d1194e --- /dev/null +++ b/tests/projects/c++/modules/stdmodules_deps_ordering/src/foo.cpp @@ -0,0 +1,5 @@ +module foo; + +auto my_sum(int a, int b) -> int { + return a + b; +} diff --git a/tests/projects/c++/modules/stdmodules_deps_ordering/src/foo.mpp b/tests/projects/c++/modules/stdmodules_deps_ordering/src/foo.mpp new file mode 100644 index 000000000..4c9a649ca --- /dev/null +++ b/tests/projects/c++/modules/stdmodules_deps_ordering/src/foo.mpp @@ -0,0 +1,3 @@ +export module foo; + +export auto my_sum(int a, int b) -> int; diff --git a/tests/projects/c++/modules/stdmodules_deps_ordering/src/main.cpp b/tests/projects/c++/modules/stdmodules_deps_ordering/src/main.cpp new file mode 100644 index 000000000..1f87ceb59 --- /dev/null +++ b/tests/projects/c++/modules/stdmodules_deps_ordering/src/main.cpp @@ -0,0 +1,8 @@ +import foo; + +import std; + +int main() { + std::cout << my_sum(1, 2) << std::endl; + return 0; +} diff --git a/tests/projects/c++/modules/stdmodules_deps_ordering/test.lua b/tests/projects/c++/modules/stdmodules_deps_ordering/test.lua new file mode 100644 index 000000000..e77adc4ae --- /dev/null +++ b/tests/projects/c++/modules/stdmodules_deps_ordering/test.lua @@ -0,0 +1 @@ +inherit(".test_stdmodules") diff --git a/tests/projects/c++/modules/stdmodules_deps_ordering/xmake.lua b/tests/projects/c++/modules/stdmodules_deps_ordering/xmake.lua new file mode 100644 index 000000000..09c3f6a94 --- /dev/null +++ b/tests/projects/c++/modules/stdmodules_deps_ordering/xmake.lua @@ -0,0 +1,19 @@ +add_rules("mode.debug", "mode.release") +set_languages("c++latest") + +-- test that a plain c++ file is ordered after all the bmis it reuses from its deps, +-- not only after the last one +-- +-- @note foo must not import std, otherwise its bmi and the std bmi +-- would not be built by two distinct jobs of the foo target +-- +-- @see https://github.com/xmake-io/xmake/issues/7690 +target("foo") + set_kind("static") + add_files("src/foo.cpp") + add_files("src/foo.mpp", {public = true}) + +target("main") + set_kind("binary") + add_deps("foo") + add_files("src/main.cpp") diff --git a/tests/projects/embed/esp32/blink/boards/esp32c3/board.h b/tests/projects/embed/esp32/blink/boards/esp32c3/board.h new file mode 100644 index 000000000..126f2c2c3 --- /dev/null +++ b/tests/projects/embed/esp32/blink/boards/esp32c3/board.h @@ -0,0 +1,7 @@ +// the board configuration of esp32c3, it's selected by the `board` option +// +// @note gpio12-17 are the spi flash of the esp32c3, do not use them +// +#pragma once + +#define LED_GPIO 8 diff --git a/tests/projects/embed/esp32/blink/src/main.c b/tests/projects/embed/esp32/blink/src/main.c new file mode 100644 index 000000000..b51e3b67b --- /dev/null +++ b/tests/projects/embed/esp32/blink/src/main.c @@ -0,0 +1,26 @@ +// blink the led of the board and print a heartbeat +// +// the led pin comes from `boards/<board>/board.h`, it's selected by the board option, +// e.g. xmake f --board=esp32c3 +// +// @note the entry is the esp-idf native `void app_main(void)`, and we print with +// `esp_rom_printf`, it writes to the rom console, which is the usb port on the +// boards booting over the native usb (usb-serial-jtag), e.g. xmake monitor +// +#include "board.h" +#include "driver/gpio.h" +#include "esp_rom_sys.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +void app_main(void) +{ + esp_rom_printf("blink: toggle gpio %d every 500ms\n", LED_GPIO); + gpio_reset_pin(LED_GPIO); + gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT); + for (int count = 0; ; count++) { + gpio_set_level(LED_GPIO, count & 1); + esp_rom_printf("blink: tick %d\n", count); + vTaskDelay(pdMS_TO_TICKS(500)); + } +} diff --git a/tests/projects/embed/esp32/blink/xmake-addons.lua b/tests/projects/embed/esp32/blink/xmake-addons.lua new file mode 100644 index 000000000..aea4ad480 --- /dev/null +++ b/tests/projects/embed/esp32/blink/xmake-addons.lua @@ -0,0 +1,2 @@ +-- the addon is installed automatically when we load this project +add_addons("esp32-devel") diff --git a/tests/projects/embed/esp32/blink/xmake.lua b/tests/projects/embed/esp32/blink/xmake.lua new file mode 100644 index 000000000..3fea2dd12 --- /dev/null +++ b/tests/projects/embed/esp32/blink/xmake.lua @@ -0,0 +1,15 @@ +-- the esp32 blink example, it needs the esp32-devel addon +-- +-- $ xmake f --board=esp32c3 +-- $ xmake +-- $ xmake install -- flash the image to the board +-- $ xmake run -- flash it and monitor the serial output +-- +includes("@addon/esp32-devel/board") + +target("blink") + add_rules("@addon/esp32-devel/app") + add_files("src/*.c") + + -- the led pin of the board, @see boards/<board>/board.h + add_includedirs("boards/" .. (get_config("board") or "esp32c3")) diff --git a/tests/projects/other/bin2c/src/asset.bin b/tests/projects/other/bin2c/src/asset.bin new file mode 100644 index 000000000..db1331f22 --- /dev/null +++ b/tests/projects/other/bin2c/src/asset.bin @@ -0,0 +1 @@ +hello transform!
\ No newline at end of file diff --git a/tests/projects/other/bin2c/src/asset2.bin b/tests/projects/other/bin2c/src/asset2.bin new file mode 100644 index 000000000..d7ffc4b96 --- /dev/null +++ b/tests/projects/other/bin2c/src/asset2.bin @@ -0,0 +1 @@ +hello luafile!
\ No newline at end of file diff --git a/tests/projects/other/bin2c/src/main.c b/tests/projects/other/bin2c/src/main.c index 74898132c..d85e9934e 100644 --- a/tests/projects/other/bin2c/src/main.c +++ b/tests/projects/other/bin2c/src/main.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <stdint.h> #include <ctype.h> +#include <string.h> static unsigned char g_bin_data[] = { #include "data.bin.h" @@ -10,6 +11,14 @@ static unsigned char g_ico_data[] = { #include "xmake.ico.h" }; +static unsigned char g_asset_data[] = { + #include "asset.bin.h" +}; + +static unsigned char g_asset2_data[] = { + #include "asset2.bin.h" +}; + static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf("%s: size: %u bytes\n", name, (unsigned int)size); if (size == 0) { @@ -94,5 +103,25 @@ int main(int argc, char** argv) hexdump("data.bin", g_bin_data, (uint32_t)sizeof(g_bin_data)); printf("\n"); hexdump("xmake.ico", g_ico_data, (uint32_t)sizeof(g_ico_data)); + printf("\n"); + hexdump("asset.bin (transformed)", g_asset_data, (uint32_t)sizeof(g_asset_data)); + printf("\n"); + hexdump("asset2.bin (transformed by lua file)", g_asset2_data, (uint32_t)sizeof(g_asset2_data)); + + // verify the function transform: asset.bin must be the reverse of "hello transform!" (+ zeroend '\0') + const char* expected = "!mrofsnart olleh"; + if (sizeof(g_asset_data) != 17 || memcmp(g_asset_data, expected, 16) != 0) { + printf("asset.bin: transform verification failed!\n"); + return 1; + } + printf("asset.bin: transform verification ok\n"); + + // verify the lua-file transform: asset2.bin must be the reverse of "hello luafile!" (+ zeroend '\0') + const char* expected2 = "!elifaul olleh"; + if (sizeof(g_asset2_data) != 15 || memcmp(g_asset2_data, expected2, 14) != 0) { + printf("asset2.bin: transform verification failed!\n"); + return 1; + } + printf("asset2.bin: transform verification ok\n"); return 0; } diff --git a/tests/projects/other/bin2c/test.lua b/tests/projects/other/bin2c/test.lua index b57362078..a23bb98a3 100644 --- a/tests/projects/other/bin2c/test.lua +++ b/tests/projects/other/bin2c/test.lua @@ -1,3 +1,5 @@ function main(t) t:build() + -- run the target, main.c verifies the transformed asset.bin and exits non-zero on mismatch + os.exec("xmake run test") end diff --git a/tests/projects/other/bin2c/transform.lua b/tests/projects/other/bin2c/transform.lua new file mode 100644 index 000000000..54cf1f394 --- /dev/null +++ b/tests/projects/other/bin2c/transform.lua @@ -0,0 +1,5 @@ +function main(inputfile, outputfile) + import("core.base.bytes") + local data = io.readfile(inputfile, {encoding = "binary"}) + io.writefile(outputfile, data:reverse(), {encoding = "binary"}) +end diff --git a/tests/projects/other/bin2c/xmake.lua b/tests/projects/other/bin2c/xmake.lua index b00dedb65..d60aea710 100644 --- a/tests/projects/other/bin2c/xmake.lua +++ b/tests/projects/other/bin2c/xmake.lua @@ -4,7 +4,15 @@ target("test") set_kind("binary") add_rules("utils.bin2c", {linewidth = 16, extensions = {".bin", ".ico"}}) add_files("src/*.c") - add_files("src/*.bin") + add_files("src/data.bin") add_files("src/xmake.ico", {nozeroend = true}) + add_files("src/asset.bin", {transform = function (inputfile, outputfile, opt) + import("core.base.bytes") + assert(bytes and opt.target) + local data = io.readfile(inputfile, {encoding = "binary"}) + io.writefile(outputfile, data:reverse(), {encoding = "binary"}) + end}) + -- transform can also be a lua script file (supported by the project generators) + add_files("src/asset2.bin", {transform = path.join(os.projectdir(), "transform.lua")}) diff --git a/tests/projects/other/bin2obj/src/asset.bin b/tests/projects/other/bin2obj/src/asset.bin new file mode 100644 index 000000000..db1331f22 --- /dev/null +++ b/tests/projects/other/bin2obj/src/asset.bin @@ -0,0 +1 @@ +hello transform!
\ No newline at end of file diff --git a/tests/projects/other/bin2obj/src/asset2.bin b/tests/projects/other/bin2obj/src/asset2.bin new file mode 100644 index 000000000..d7ffc4b96 --- /dev/null +++ b/tests/projects/other/bin2obj/src/asset2.bin @@ -0,0 +1 @@ +hello luafile!
\ No newline at end of file diff --git a/tests/projects/other/bin2obj/src/main.c b/tests/projects/other/bin2obj/src/main.c index bc1d2442f..03c50352d 100644 --- a/tests/projects/other/bin2obj/src/main.c +++ b/tests/projects/other/bin2obj/src/main.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <stdint.h> #include <ctype.h> +#include <string.h> extern const uint8_t _binary_data_bin_start[]; extern const uint8_t _binary_data_bin_end[]; @@ -8,30 +9,39 @@ extern const uint8_t _binary_data_bin_end[]; extern const uint8_t _binary_xmake_ico_start[]; extern const uint8_t _binary_xmake_ico_end[]; +extern const uint8_t _binary_asset_bin_start[]; +extern const uint8_t _binary_asset_bin_end[]; + +extern const uint8_t _binary_asset2_bin_start[]; +extern const uint8_t _binary_asset2_bin_end[]; + +extern const uint8_t _binary_asset2_bin_start[]; +extern const uint8_t _binary_asset2_bin_end[]; + static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf("%s: size: %u bytes\n", name, (unsigned int)size); if (size == 0) { return; } - + // if file is larger than 128 bytes, only dump first 64 and last 64 bytes uint32_t dump_size = size; uint32_t start_offset = 0; uint32_t end_offset = 0; uint32_t skip_size = 0; - + if (size > 128) { dump_size = 64; start_offset = 0; end_offset = size - 64; skip_size = end_offset - start_offset - dump_size; } - + // dump start for (uint32_t offset = start_offset; offset < start_offset + dump_size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); - + // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { @@ -43,7 +53,7 @@ static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf(" "); } } - + // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { @@ -52,18 +62,18 @@ static void hexdump(const char* name, const uint8_t* data, uint32_t size) { } printf("|\n"); } - + // print skip indicator if needed if (skip_size > 0) { printf(" ... (skipped %u bytes) ...\n", (unsigned int)skip_size); } - + // dump end if needed if (size > 128) { for (uint32_t offset = end_offset; offset < size; offset += 16) { // print offset printf("%08x ", (unsigned int)offset); - + // print hex bytes (8 bytes, space, 8 bytes) for (uint32_t i = 0; i < 16; i++) { if (offset + i < size) { @@ -75,7 +85,7 @@ static void hexdump(const char* name, const uint8_t* data, uint32_t size) { printf(" "); } } - + // print ASCII representation printf(" |"); for (uint32_t i = 0; i < 16 && offset + i < size; i++) { @@ -90,9 +100,31 @@ static void hexdump(const char* name, const uint8_t* data, uint32_t size) { int main(int argc, char** argv) { const uint32_t _binary_data_bin_size = (uint32_t)(_binary_data_bin_end - _binary_data_bin_start); const uint32_t _binary_xmake_ico_size = (uint32_t)(_binary_xmake_ico_end - _binary_xmake_ico_start); + const uint32_t _binary_asset_bin_size = (uint32_t)(_binary_asset_bin_end - _binary_asset_bin_start); + const uint32_t _binary_asset2_bin_size = (uint32_t)(_binary_asset2_bin_end - _binary_asset2_bin_start); hexdump("data.bin", _binary_data_bin_start, _binary_data_bin_size); printf("\n"); hexdump("xmake.ico", _binary_xmake_ico_start, _binary_xmake_ico_size); + printf("\n"); + hexdump("asset.bin (transformed)", _binary_asset_bin_start, _binary_asset_bin_size); + printf("\n"); + hexdump("asset2.bin (transformed by lua file)", _binary_asset2_bin_start, _binary_asset2_bin_size); + + // verify the function transform: asset.bin must be the reverse of "hello transform!" (+ zeroend '\0') + const char* expected = "!mrofsnart olleh"; + if (_binary_asset_bin_size != 17 || memcmp(_binary_asset_bin_start, expected, 16) != 0) { + printf("asset.bin: transform verification failed!\n"); + return 1; + } + printf("asset.bin: transform verification ok\n"); + + // verify the lua-file transform: asset2.bin must be the reverse of "hello luafile!" (+ zeroend '\0') + const char* expected2 = "!elifaul olleh"; + if (_binary_asset2_bin_size != 15 || memcmp(_binary_asset2_bin_start, expected2, 14) != 0) { + printf("asset2.bin: transform verification failed!\n"); + return 1; + } + printf("asset2.bin: transform verification ok\n"); return 0; } diff --git a/tests/projects/other/bin2obj/test.lua b/tests/projects/other/bin2obj/test.lua index 7f2050b62..a75aa7e40 100644 --- a/tests/projects/other/bin2obj/test.lua +++ b/tests/projects/other/bin2obj/test.lua @@ -1,4 +1,6 @@ function main(t) t:build() + -- run the target, main.c verifies the transformed asset.bin and exits non-zero on mismatch + os.exec("xmake run test") end diff --git a/tests/projects/other/bin2obj/transform.lua b/tests/projects/other/bin2obj/transform.lua new file mode 100644 index 000000000..54cf1f394 --- /dev/null +++ b/tests/projects/other/bin2obj/transform.lua @@ -0,0 +1,5 @@ +function main(inputfile, outputfile) + import("core.base.bytes") + local data = io.readfile(inputfile, {encoding = "binary"}) + io.writefile(outputfile, data:reverse(), {encoding = "binary"}) +end diff --git a/tests/projects/other/bin2obj/xmake.lua b/tests/projects/other/bin2obj/xmake.lua index 9541e17ae..d383bb1bb 100644 --- a/tests/projects/other/bin2obj/xmake.lua +++ b/tests/projects/other/bin2obj/xmake.lua @@ -6,3 +6,11 @@ target("test") add_files("src/*.c") add_files("src/data.bin", {zeroend = true}) add_files("src/xmake.ico", {zeroend = false}) + add_files("src/asset.bin", {zeroend = true, transform = function (inputfile, outputfile, opt) + import("core.base.bytes") + assert(bytes and opt.target) + local data = io.readfile(inputfile, {encoding = "binary"}) + io.writefile(outputfile, data:reverse(), {encoding = "binary"}) + end}) + -- transform can also be a lua script file (supported by the project generators) + add_files("src/asset2.bin", {zeroend = true, transform = path.join(os.projectdir(), "transform.lua")}) diff --git a/xmake/actions/addon/main.lua b/xmake/actions/addon/main.lua new file mode 100644 index 000000000..99f92d125 --- /dev/null +++ b/xmake/actions/addon/main.lua @@ -0,0 +1,334 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file main.lua +-- + +-- imports +import("core.base.option") +import("core.package.addon") +import("core.project.project") +import("devel.git") +import("private.action.addon.impl.install_addons") +import("private.action.addon.impl.xrepo", {alias = "xrepo_addon"}) +import("private.action.require.impl.environment") +import("private.action.require.impl.search_packages") + +-- validate an addon directory name +function _check_addon_name(name) + assert(type(name) == "string" and name ~= "" and name ~= "." and not name:find("..", 1, true) and not name:find("[/\\:]"), "invalid addon name(%s)!", name) + return name +end + +-- get addon directory in ~/.xmake/addons +function _get_addondir(name, version) + local addondir = addon.installdir() + if name then + addondir = path.join(addondir, addon.dirname(_check_addon_name(name))) + if version then + addondir = path.join(addondir, version) + end + end + return addondir +end + +-- install the given addons from the repositories which provide them +-- +-- @note we install them in one shot, xrepo resolves and installs them in parallel +-- +function _install_from_repo(names) + for _, name in ipairs(names) do + -- e.g. myrepo@myaddon + _check_addon_name(name:split("@", {plain = true, limit = 2})[2] or name) + end + xrepo_addon("install", names, {force = option.get("force")}) +end + +-- install a single addon from a source directory (as the given name, default to the directory name) +function _install_from_local(dir, name) + assert(os.isdir(dir), "addon path(%s) not found!", dir) + + -- we need to normalize it first, e.g. `/path/to/myaddon/` -> `/path/to/myaddon`, + -- otherwise we cannot get the addon name from the directory + dir = path.normalize(path.absolute(dir)) + + -- we only install the payload directories, the addon repository may have its own files, + -- e.g. tests, ci scripts and documents, and they can also be placed in the `src` subdirectory + local payloadroot = addon.payloadroot(dir) + assert(payloadroot, "addon path(%s): no payload directory found, e.g. ${bright}plugins${clear}!", dir) + + -- the addon describes itself? its manifest is always authoritative, + -- otherwise we can only guess its name from the directory name + local manifest = addon.manifest(dir) + if manifest then + name = manifest.name + end + name = name or path.filename(dir) + + -- the addons installed from a local directory or a git url have no semantic version + local version = "latest" + local dstdir = _get_addondir(name, version) + assert(not os.isdir(dstdir), "addon(%s) already exists!", name) + + -- the addons which it depends on are not installed by the local installation, + -- so we need to install them from the repositories first + if manifest then + for _, dep in ipairs(manifest.deps) do + if not addon.addons()[addon.dirname(dep)] then + _install_from_repo({dep}) + end + end + end + + for _, payloaddir in ipairs(addon.payloads_of(payloadroot)) do + os.vcp(path.join(payloadroot, payloaddir), path.join(dstdir, payloaddir)) + end + + -- we need to roll back the installed payloads if it cannot be registered, e.g. the name conflicts + try + { + function () + addon.register(name, version, manifest and { + description = manifest.description, + deps = #manifest.deps > 0 and manifest.deps or nil, + globalmodules = #manifest.globalmodules > 0 and manifest.globalmodules or nil}) + end, + catch + { + function (errors) + os.tryrm(dstdir) + -- we need to remove the addon directory too if no other version is installed + local addondir = path.directory(dstdir) + if #os.filedirs(path.join(addondir, "*")) == 0 then + os.tryrm(addondir) + end + raise(errors) + end + } + } + cprint("${color.success}install ${bright}%s${clear} ok!", name) +end + +-- install a single addon from a git url or github shortcut, e.g. https://github.com/xmake-addons/serial-monitor +function _install_from_git(url) + local branch + if url:startswith("github:") then + local i = url:find("#", 1, true) + if i then + branch = url:sub(i + 1) + url = url:sub(1, i - 1) + end + url = git.asgiturl(url) + end + local name = (path.filename(url):gsub("%.git$", "")) + local tmpdir = os.tmpfile() .. ".dir" + + -- we need git to clone it, it will be installed first if it's not found + -- + -- @note we cannot enter it for the other install paths, it may install packages + -- and that needs a project, but `xmake addon` can be run anywhere + -- + environment.enter() + try + { + function () + git.clone(url, {verbose = option.get("verbose"), branch = branch, outputdir = tmpdir}) + os.tryrm(path.join(tmpdir, ".git")) + _install_from_local(tmpdir, name) + end, + finally + { + -- we always need to remove the temporary clone directory, + -- @note try() swallows the errors if we do not re-raise them here + function (ok, errors) + os.tryrm(tmpdir) + if not ok then + raise(errors) + end + end + } + } + environment.leave() +end + +-- does the given name come from a repository? e.g. `myaddon`, `myrepo@myaddon` +function _is_from_repo(name) + -- github shortcut: github:user/repo or github:user/repo#branch + if name:startswith("github:") then + return false + end + + -- local directory + -- + -- @note we need to check it before the git url, `git.asgiturl` also accepts + -- the local paths with a trailing separator, e.g. `/path/to/myaddon/` + if os.isdir(name) then + return false + end + return not git.asgiturl(name) +end + +-- install addons +function _install() + local names = assert(option.get("addons"), "please specify the addons to be installed!") + + -- the addons from the repositories are installed in one shot, the others one by one + local requires = {} + for _, name in ipairs(names) do + if _is_from_repo(name) then + table.insert(requires, name) + elseif os.isdir(name) then + _install_from_local(name) + else + _install_from_git(name) + end + end + if #requires > 0 then + _install_from_repo(requires) + end +end + +-- remove the given installed addons +-- +-- @note `xrepo remove --addon` removes them in the same way, +-- @see xmake/modules/private/xrepo/action/remove.lua +-- +function _remove() + local names = option.get("addons") + local force = option.get("force") + + -- remove all the installed addons? e.g. xmake addon --remove --all + if option.get("all") then + names = table.keys(addon.addons()) + if #names == 0 then + wprint("no installed addons!") + return + end + -- the dependencies between them do not matter, they are all removed + force = true + end + + assert(names, "please specify the addon name to be removed!") + for _, name in ipairs(names) do + addon.remove(name, {force = force}) + cprint("${color.success}remove ${bright}%s${clear} ok!", name) + end +end + +-- upgrade the addons which the current project declares, e.g. add_addons("esp32-devel 1.0.x") +function _upgrade() + local declarations = {addons = table.wrap(project.get("addons")), + repositories = table.wrap(project.get("repositories"))} + assert(#declarations.addons > 0, "no addons are declared in this project, e.g. add_addons(\"esp32-devel\")!") + install_addons(os.projectdir(), declarations, {upgrade = true}) +end + +-- search the addons from the repositories +function _search() + local patterns = assert(option.get("addons"), "please specify the addon name pattern to be searched!") + xrepo_addon("search", patterns) +end + +-- collect the installed addons from the addons registry +function _collect_installed_addons() + local entries = {} + for name, addoninfo in table.orderpairs(addon.addons()) do + -- an addon can be installed with several versions, we show the active one, + -- the projects can lock the other ones, @see core/project/addons.lua + local versions = addon.versions(name) + table.insert(entries, {name = name, version = addoninfo.version, + versions = #versions > 1 and versions or nil, + description = addoninfo.description, payloads = addoninfo.payloads}) + end + return entries +end + +-- print an addon entry, e.g. -> serial-monitor v1.0.1: monitor the serial port output (in xmake-repo) +function _print_addon(entry, suffix) + local title = entry.name + if entry.version then + title = title .. " " .. entry.version + end + local description = entry.description and (": " .. entry.description) or "" + cprint(" ${color.dump.reference}->${clear} ${color.dump.string}%s${clear}%s%s", title, description, suffix or "") +end + +-- get the addons in the repositories, we reuse the packages search here +function _collect_repo_addons(exclude) + local entries = {} + for _, results in table.orderpairs(search_packages({"*"}, {kind = "addon", description = false})) do + for _, result in ipairs(results) do + if not exclude[result.name] then + table.insert(entries, result) + end + end + end + table.sort(entries, function (a, b) return a.name < b.name end) + return entries +end + +-- list all addons +function _list() + + -- show the installed addons + local installed = _collect_installed_addons() + local exclude = {} + cprint("${bright}the installed addons:${clear}") + if #installed > 0 then + for _, entry in ipairs(installed) do + exclude[entry.name] = true + local suffix = string.format(" ${dim}(%s)${clear}", table.concat(entry.payloads, ", ")) + if entry.versions then + suffix = suffix .. string.format(" ${dim}[installed: %s]${clear}", table.concat(entry.versions, ", ")) + end + _print_addon(entry, suffix) + end + else + print(" (none)") + end + + -- show the addons in the repositories, we only show the first ones if there are too many + local listlimit = 10 + local avail = _collect_repo_addons(exclude) + cprint("${bright}the available addons:${clear} ${dim}(run `xmake addon --install <name>` to install," .. + " `--search <pattern>` to search)${clear}") + if #avail > 0 then + for idx, entry in ipairs(avail) do + if idx > listlimit then + cprint(" ${dim}... and %d more${clear}", #avail - listlimit) + break + end + _print_addon(entry, entry.reponame and string.format(" ${dim}(in %s)${clear}", entry.reponame) or nil) + end + else + print(" (none)") + end +end + +function main() + if option.get("install") then + _install() + elseif option.get("remove") then + _remove() + elseif option.get("upgrade") then + _upgrade() + elseif option.get("list") then + _list() + elseif option.get("search") then + _search() + end +end diff --git a/xmake/actions/addon/xmake.lua b/xmake/actions/addon/xmake.lua new file mode 100644 index 000000000..a0266aa4f --- /dev/null +++ b/xmake/actions/addon/xmake.lua @@ -0,0 +1,49 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file xmake.lua +-- + +task("addon") + set_category("action") + on_run("main") + set_menu { + usage = "xmake addon [options]", + description = "Manage addons of xmake.", + options = { + {'i', "install", "k", nil, "Install addons."}, + {'r', "remove", "k", nil, "Remove the given installed addons."}, + {'s', "search", "k", nil, "Search the addons from the repositories."}, + {'l', "list", "k", nil, "List all installed addons."}, + {'u', "upgrade", "k", nil, "Upgrade the addons which the current project declares."}, + {nil, "all", "k", nil, "Remove all installed addons, e.g. xmake addon --remove --all"}, + {'f', "force", "k", nil, "Force to remove the addons, even if they are depended on by the others."}, + {nil, "addons", "vs", nil, "The addon paths, urls or names.", + "e.g.", + " $ xmake addon --install https://github.com/myrepo/serial-monitor", + " $ xmake addon --install github:myrepo/serial-monitor", + " $ xmake addon --install github:myrepo/serial-monitor#dev", + " $ xmake addon --install /tmp/my-addon", + " $ xmake addon --install xmake-repo@serial-monitor", + " $ xmake addon --install serial-monitor", + " $ xmake addon --remove serial-monitor", + " $ xmake addon --remove --all", + " $ xmake addon --upgrade", + " $ xmake addon --search serial", + " $ xmake addon --list"} + } + } diff --git a/xmake/actions/create/main.lua b/xmake/actions/create/main.lua index 89a4791a6..f3135fadb 100644 --- a/xmake/actions/create/main.lua +++ b/xmake/actions/create/main.lua @@ -25,6 +25,19 @@ import("actions.create.template", {rootdir = os.programdir()}) -- validate template component against path traversal function _validate_template_component(name, value) + + -- the qualified template id of an addon, e.g. @addon/basic-templates/verilator.console + if name == "template id" and value:startswith("@addon/") then + local rest = value:sub(#"@addon/" + 1) + local pos = rest:find("/", 1, true) + if not pos then + raise("invalid %s: %s, it should be `@addon/<addon>/<template>`!", name, value) + end + _validate_template_component("addon name", rest:sub(1, pos - 1)) + _validate_template_component("template id", rest:sub(pos + 1)) + return + end + if #value == 0 or value == "." or value == ".." or value:find("/", 1, true) or value:find("\\", 1, true) or value:find(":", 1, true) or value:find("\0", 1, true) then @@ -79,26 +92,12 @@ function _list_templates(lang_filter) languages = {lang_filter} end - -- map a template directory to its root meta (repo/global/builtin) - local rootinfo_of = function (dir) - if not dir then - return - end - dir = path.absolute(dir) - for _, info in ipairs(rootinfos) do - local rootdir = path.absolute(info.dir) - if dir == rootdir or dir:startswith(rootdir .. path.sep()) then - return info - end - end - end - local sourcekey_of = function (info) if not info then return "unknown" end - if info.kind == "repo" then - return "repo:" .. info.name + if info.kind == "addon" then + return info.kind .. ":" .. info.name end return info.kind or "unknown" end @@ -109,7 +108,7 @@ function _list_templates(lang_filter) if templates and #templates > 0 then for _, name in ipairs(templates) do local sourcedir = template.templatedir(lang, name) - local info = rootinfo_of(sourcedir) + local info = template.rootinfo_of(sourcedir) local key = sourcekey_of(info) local group = groups[key] if not group then @@ -140,9 +139,8 @@ function _list_templates(lang_filter) local group = groups[key] if group then local info = group.info - if info and info.kind == "repo" then - local branch = info.branch and (" " .. info.branch) or "" - cprint("${bright}%s${reset}: %s%s", info.name, info.url or "", branch) + if info and info.kind == "addon" then + cprint("${bright}%s${reset}: addon %s", info.name, info.version or "") else cprint("${bright}%s${reset}", (info and info.kind) or "unknown") end @@ -195,7 +193,7 @@ function _create_project(lang, templateid, targetname) -- create project local sourcedir = template.templatedir(lang, templateid) if not sourcedir then - raise("template(%s/%s): not found!\nyou can try:\n - xrepo update-repo (update repositories)\n - xmake create --list (show available templates)", lang, templateid) + raise("template(%s/%s): not found!\nyou can try:\n - xmake addon --search templates (search the addons which provide templates)\n - xmake create --list (show available templates)", lang, templateid) end -- get the builtin variables diff --git a/xmake/actions/create/template.lua b/xmake/actions/create/template.lua index 1279c1d35..ac39e2ff8 100644 --- a/xmake/actions/create/template.lua +++ b/xmake/actions/create/template.lua @@ -22,7 +22,7 @@ import("core.base.global") import("core.base.hashset") import("core.language.language") -import("core.package.repository") +import("core.package.addon") -- some builtin template variables in xmake.lua function builtinvars(targetname) @@ -33,19 +33,16 @@ end -- get all template roots with extra meta information -- -- priority: --- 1. repo: <global-repo>/templates (including builtin repo templates) +-- 1. addon: <globaldir>/addons/<name>/<version>/templates -- 2. global: <globaldir>/templates +-- 3. builtin: <programdir>/templates function rootinfos() local results = {} - -- get template directories from global repositories - local repos = repository.repositories({global = true, network = false}) - if repos then - for _, repo in ipairs(repos) do - local templatesdir = path.join(repo:directory(), "templates") - if os.isdir(templatesdir) then - table.insert(results, {kind = "repo", name = repo:name(), url = repo:url(), branch = repo:branch(), dir = templatesdir}) - end + -- get template directories from the installed addons + for _, addoninfo in ipairs(addon.payloadinfos("templates")) do + if os.isdir(addoninfo.dir) then + table.insert(results, {kind = "addon", name = addoninfo.name, version = addoninfo.version, dir = addoninfo.dir}) end end @@ -54,9 +51,31 @@ function rootinfos() if os.isdir(dir) then table.insert(results, {kind = "global", dir = dir}) end + dir = path.join(os.programdir(), "templates") + if os.isdir(dir) then + table.insert(results, {kind = "builtin", dir = dir}) + end return results end +-- get the root information of the given template directory +-- +-- @param templatedir the template directory, e.g. <programdir>/templates/c/console +-- @return the root information, @see rootinfos +-- +function rootinfo_of(templatedir) + if not templatedir then + return + end + templatedir = path.absolute(templatedir) + for _, info in ipairs(rootinfos()) do + local rootdir = path.absolute(info.dir) + if templatedir == rootdir or templatedir:startswith(rootdir .. path.sep()) then + return info + end + end +end + -- get template root directories function rootdirs() local results = {} @@ -83,6 +102,23 @@ end function templatedir(lang, templateid) assert(lang) assert(templateid) + + -- the qualified template of an addon, e.g. @addon/basic-templates/verilator.console + -- + -- @note the template ids are not namespaced, we only need it to disambiguate the conflicts + -- + if templateid:startswith("@addon/") then + local referenceinfo = addon.resolve_reference(templateid, "/", "templates") + local subdir = _templateid_subdir(referenceinfo.name) + if subdir then + local dir = path.join(referenceinfo.dir, lang, subdir) + if os.isfile(path.join(dir, "xmake.lua")) then + return dir + end + end + return + end + for _, rootdir in ipairs(rootdirs()) do local subdir = _templateid_subdir(templateid) if subdir then @@ -154,11 +190,21 @@ function languages() return results end +-- get the reference of the given template, e.g. @addon/basic-templates/verilator.console +function _template_reference(rootinfo, templateid) + if rootinfo.kind == "addon" then + return string.format("@addon/%s/%s", rootinfo.name, templateid) + end + return path.join(rootinfo.dir, templateid) +end + -- get all templates for the given language function templates(lang) assert(lang) local found = hashset.new() - for _, rootdir in ipairs(rootdirs()) do + local providers = {} + for _, rootinfo in ipairs(rootinfos()) do + local rootdir = rootinfo.dir local templateroot = path.join(rootdir, lang) local configfiles = os.files(path.join(templateroot, "**", "xmake.lua")) if configfiles then @@ -182,7 +228,17 @@ function templates(lang) end if ok then table.insert(accepted, item.dir) - found:insert((item.relpath:gsub("[/\\]", "."))) + local templateid = (item.relpath:gsub("[/\\]", ".")) + -- the templates are not namespaced, so we need to report the conflicts of the addons, + -- otherwise we do not know which template will be used + local provider = providers[templateid] + if provider and (provider.kind == "addon" or rootinfo.kind == "addon") then + wprint("template(%s/%s) conflicts, we will use the first one!\n -> %s\n -> %s\nplease use the qualified template id to disambiguate them.", + lang, templateid, _template_reference(provider, templateid), _template_reference(rootinfo, templateid)) + else + providers[templateid] = rootinfo + found:insert(templateid) + end end end end diff --git a/xmake/actions/require/xmake.lua b/xmake/actions/require/xmake.lua index bf81e3810..b800c4528 100644 --- a/xmake/actions/require/xmake.lua +++ b/xmake/actions/require/xmake.lua @@ -39,6 +39,9 @@ task("require") {nil, "linkjobs", "kv", nil, "Set the number of parallel link jobs."}, {nil, "shallow", "k", nil, "Does not install or download dependent packages."}, {nil, "build", "k", nil, "Always build and install packages from source."}, + {nil, "addon", "k", nil, "Install addon packages from <repository>/addons/."}, + {nil, "plugin", "k", nil, "Install plugin packages from <repository>/plugins/.", + "(deprecated, please use --addon instead)"}, {'l', "list", "k", nil, "List all package dependencies in project.", "e.g.", " $ xmake require --list"}, diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua index 83bbdf593..8dc0e4880 100644 --- a/xmake/core/base/interpreter.lua +++ b/xmake/core/base/interpreter.lua @@ -879,6 +879,33 @@ function interpreter:scriptdir() return path.directory(self._PRIVATE._CURFILE) end +-- add a resolver for the references of includes(), e.g. includes("@addon/esp32/check") +-- +-- @param resolver function (interp, reference), it returns the files, or nil and errors +-- +-- @note the interpreter knows nothing about the references, the callers register the +-- resolvers which they support, e.g. @see project._interpreter() +-- +function interpreter:includes_resolver_add(resolver) + local resolvers = self._PRIVATE._INCLUDES_RESOLVERS or {} + table.insert(resolvers, resolver) + self._PRIVATE._INCLUDES_RESOLVERS = resolvers +end + +-- do we ignore the unresolvable references of includes()? e.g. includes("@addon/esp32/board") +function interpreter:includes_unresolved() + return self._PRIVATE._INCLUDES_UNRESOLVED +end + +-- ignore the unresolvable references of includes() instead of raising errors +-- +-- @note the project file may reference the resources which have not been installed yet, +-- so the caller can load it, install them and load it again, @see project._load() +-- +function interpreter:includes_unresolved_set(enabled) + self._PRIVATE._INCLUDES_UNRESOLVED = enabled +end + -- set root scope kind -- -- the root api will affect these scopes @@ -1786,6 +1813,15 @@ function interpreter:api_builtin_set_xmakever(minver) end -- the builtin api: includes() +-- find the include files of the builtin includes, e.g. includes("@builtin/check") +function interpreter:_find_builtin_includes(subpath) + local builtin_path = subpath:sub(#"@builtin/" + 1) + if builtin_path:endswith(".lua") then + return os.files(path.join(os.programdir(), "includes", builtin_path)) + end + return os.files(path.join(os.programdir(), "includes", builtin_path, "xmake.lua")) +end + function interpreter:api_builtin_includes(...) assert(self and self._PRIVATE and self._PRIVATE._ROOTDIR and self._PRIVATE._MTIMES) local curfile = self._PRIVATE._CURFILE @@ -1799,18 +1835,31 @@ function interpreter:api_builtin_includes(...) -- attempt to find files from programdir/includes/*.lua -- e.g. includes("@builtin/check") if subpath:startswith("@builtin/") then - local builtin_path = subpath:sub(10) - local files - if builtin_path:endswith(".lua") then - files = os.files(path.join(os.programdir(), "includes", builtin_path)) - else - files = os.files(path.join(os.programdir(), "includes", builtin_path, "xmake.lua")) - end + local files = self:_find_builtin_includes(subpath) if files and #files > 0 then table.join2(subpaths_matched, files) found = true end end + -- attempt to find files from the registered resolvers of the references + -- e.g. includes("@addon/esp32/check"), @see interpreter:includes_resolver_add() + if not found and subpath:startswith("@") then + for _, resolver in ipairs(self._PRIVATE._INCLUDES_RESOLVERS or {}) do + local files, errors = resolver(self, subpath) + if files then + table.join2(subpaths_matched, files) + found = true + break + elseif errors then + -- it has not been resolved yet? the caller may load this file again + if self:includes_unresolved() then + found = true + break + end + os.raise(errors) + end + end + end -- find the given files from the project directory if not found then local files diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua index 005f18a70..89be6d638 100644 --- a/xmake/core/base/os.lua +++ b/xmake/core/base/os.lua @@ -423,8 +423,14 @@ function os.match(pattern, mode, opt) return os._async_task().match(pattern, mode) end - -- extract callback - local callback = type(opt) == "function" and opt or (type(opt) == "table" and opt.callback or nil) + -- extract callback and the maximum recursion level + local callback, maxrecursion + if type(opt) == "function" then + callback = opt + elseif type(opt) == "table" then + callback = opt.callback + maxrecursion = opt.recursion + end -- support path instance pattern = tostring(pattern) @@ -493,7 +499,9 @@ function os.match(pattern, mode, opt) -- limit recursion level: src/*/*.c local recursion = 0 if pattern:find("**", 1, true) then - recursion = -1 + -- we can also limit the recursion level of `**`, it may be very slow + -- in a deep directory tree, e.g. os.files("src/**.c", {recursion = 2}) + recursion = maxrecursion or -1 else -- "src/*/*.c" -> "*/" -> recursion level: 1 -- "src/*/main.c" -> "*/" -> recursion level: 1 @@ -504,6 +512,9 @@ function os.match(pattern, mode, opt) recursion = seps end end + if maxrecursion and recursion > maxrecursion then + recursion = maxrecursion + end end -- convert pattern to a lua pattern diff --git a/xmake/core/base/poller.lua b/xmake/core/base/poller.lua index bb18dfda4..43c3bea1a 100644 --- a/xmake/core/base/poller.lua +++ b/xmake/core/base/poller.lua @@ -124,7 +124,7 @@ function poller:remove(obj) end -- remove poller object data - self:_pollerdata_set(obj, nil) + self:_pollerdata_set(obj:cdata(), nil) return true end @@ -153,13 +153,15 @@ function poller:wait(timeout) local otype = v[1] local cdata = v[2] local events = v[3] - local pollerdata = self:_pollerdata(cdata) - if not pollerdata then - return -1, string.format("no object data for cdata(%s)!", cdata) + -- this object may have been removed from the poller while its event + -- was already collected, e.g. a pending overlapped io on windows, + -- we just drop it, it has no owner any more, @see poller:remove() + local pollerdata = self:_pollerdata(cdata) + if pollerdata then + local obj = pollerdata[1] + assert(obj and obj:otype() == otype and obj:cdata() == cdata) + table.insert(results, {obj, events, pollerdata[2]}) end - local obj = pollerdata[1] - assert(obj and obj:otype() == otype and obj:cdata() == cdata) - table.insert(results, {obj, events, pollerdata[2]}) end end return count, results diff --git a/xmake/core/base/scheduler.lua b/xmake/core/base/scheduler.lua index a59c38207..4ae8d74e0 100644 --- a/xmake/core/base/scheduler.lua +++ b/xmake/core/base/scheduler.lua @@ -304,9 +304,17 @@ end function scheduler:_poller_events_cb(obj, events) -- get poller object data + -- + -- the object may have been cancelled while its event was already queued, + -- e.g. a process which exits right after we stopped waiting for it, + -- @see scheduler:poller_cancel() + -- + -- such an event has no owner any more, we just drop it: it is not an + -- error of the scheduler and it must not abort the whole loop local pollerdata = self:_poller_data(obj) if not pollerdata then - return false, string.format("%s: cannot get poller data!", obj) + utils.dprint("%s: drop the event(%d), it has been cancelled!", obj, events) + return true end -- is process/fwatcher object? @@ -1068,6 +1076,10 @@ function scheduler:poller_waitproc(obj, timeout) running:waitobj_set(obj) -- wait + -- + -- @note we keep this process in the poller if it is timeout, so its exit status + -- is still saved as a pending status when it exits later, and the next wait + -- returns it immediately, @see scheduler:_poller_events_cb() local ok = self:co_suspend() return ok, pollerdata.object_event end diff --git a/xmake/core/base/semver.lua b/xmake/core/base/semver.lua index 7c2b6ea8d..fc989e18d 100644 --- a/xmake/core/base/semver.lua +++ b/xmake/core/base/semver.lua @@ -232,5 +232,15 @@ function semver.match(str, pos, pattern) end end +-- is a valid semantic version? e.g. "1.2.3", "v1.2.3-beta" +function semver.is_valid(version) + return semver.parse(version) ~= nil +end + +-- is a valid semantic version range? e.g. ">=1.0 <2.0", "^1.2", "master || >1.4" +function semver.is_valid_range(range) + return semver.satisfies("1.0", range) ~= nil +end + -- return module: semver return semver diff --git a/xmake/core/base/task.lua b/xmake/core/base/task.lua index 27ad5023a..2b3788603 100644 --- a/xmake/core/base/task.lua +++ b/xmake/core/base/task.lua @@ -24,10 +24,12 @@ local task = task or {} -- load modules local os = require("base/os") local table = require("base/table") +local utils = require("base/utils") local string = require("base/string") local global = require("base/global") local hashset = require("base/hashset") local interpreter = require("base/interpreter") +local addon = require("package/addon") local sandbox = require("sandbox/sandbox") local config = require("project/config") local sandbox_os = require("sandbox/modules/os") @@ -81,9 +83,23 @@ end -- the directories of tasks function task._directories() - return {path.join(global.directory(), "plugins"), - path.join(os.programdir(), "plugins"), - path.join(os.programdir(), "actions")} + local dirs = task._DIRECTORIES + if dirs == nil then + -- add the plugins of the installed addons first, e.g. ~/.xmake/addons/<name>/<version>/plugins + -- + -- we get them from the addons registry file directly, + -- so we do not need to scan the whole addons directory on startup + -- + -- @note the first one wins, so an addon is able to take over a deprecated + -- builtin plugin, e.g. `xmake format` + -- + dirs = addon.payloads("plugins") + table.insert(dirs, path.join(global.directory(), "plugins")) + table.insert(dirs, path.join(os.programdir(), "plugins")) + table.insert(dirs, path.join(os.programdir(), "actions")) + task._DIRECTORIES = dirs + end + return dirs end -- translate menu @@ -96,7 +112,7 @@ function task._translate_menu(taskname, menu) local options_full = {} for _, opt in ipairs(options) do if type(opt) == "function" then - local ok, results = sandbox.load(opt) + local ok, results = sandbox.call(opt) if ok then if results then for _, opt in ipairs(results) do @@ -141,7 +157,7 @@ function task._translate_menu(taskname, menu) opt[i] = function () -- call it in the sandbox - local ok, results = sandbox.load(description) + local ok, results = sandbox.call(description) if not ok then return nil, string.format("taskmenu: %s", results) end @@ -385,6 +401,39 @@ function task.new(name, info) return instance end +-- is the given plugin conflicting with the loaded one? +-- +-- the plugins are not namespaced, so the first one always wins, @see task._directories(), +-- but we need to report the conflicts of the addons, otherwise we do not know which +-- plugin will be run +-- +-- @param taskname the task name +-- @param taskfile the task file of the loaded plugin, it will be nil if it's the first one +-- @param filepath the task file of the plugin which we are loading +-- +function task._is_conflicting(taskname, taskfile, filepath) + if not taskfile then + return false + end + + -- we only report it if both of them come from the addons, taking over a builtin + -- plugin is expected, e.g. `xmake format` has been moved to an addon + -- + -- @note we cannot raise errors here, otherwise all the commands will be broken, + -- and the user cannot even remove the conflicting addons + local addondir = path.absolute(addon.installdir()) + if path.absolute(taskfile):startswith(addondir) and path.absolute(filepath):startswith(addondir) then + utils.warning("plugin(%s) conflicts, we will use the first one!\n -> %s\n -> %s", taskname, taskfile, filepath) + end + return true +end + +-- clear the loaded tasks, e.g. some addons may be installed just now +function task.clear() + task._TASKS = nil + task._DIRECTORIES = nil +end + -- get all registered tasks -- -- @return the tasks table {name = task, ...} @@ -396,6 +445,7 @@ function task.tasks() -- load tasks local tasks = {} + local taskfiles = {} local dirs = task._directories() for _, dir in ipairs(dirs) do local files = os.files(path.join(dir, "*", "xmake.lua")) @@ -403,7 +453,12 @@ function task.tasks() for _, filepath in ipairs(files) do local results, errors = task._load(filepath) if results then - table.join2(tasks, results) + for taskname, taskinfo in pairs(results) do + if not task._is_conflicting(taskname, taskfiles[taskname], filepath) then + taskfiles[taskname] = filepath + tasks[taskname] = taskinfo + end + end else os.raise(errors) end @@ -508,7 +563,7 @@ function task:run(...) local curdir = os.curdir() -- run task - local ok, errors = sandbox.load(on_run, ...) + local ok, errors = sandbox.call(on_run, ...) -- restore the current directory os.cd(curdir) diff --git a/xmake/core/base/thread.lua b/xmake/core/base/thread.lua index 187f98d53..6c3fc5169 100644 --- a/xmake/core/base/thread.lua +++ b/xmake/core/base/thread.lua @@ -942,7 +942,7 @@ function thread._run_thread(callback_str, callinfo_str) end -- do callback - local ok, errors = sandbox.load(sandbox_inst:script(), table.unpack(argv or {})) + local ok, errors = sandbox.call(sandbox_inst:script(), table.unpack(argv or {})) -- thread is finished, we need to notify the waited thread if wpipe then diff --git a/xmake/core/language/language.lua b/xmake/core/language/language.lua index 8c6846819..1ea960807 100644 --- a/xmake/core/language/language.lua +++ b/xmake/core/language/language.lua @@ -50,7 +50,7 @@ function _instance:get(name) end if self._g == nil and info.load ~= nil then - local ok, results = sandbox.load(info.load) + local ok, results = sandbox.call(info.load) if not ok then os.raise(results) end diff --git a/xmake/core/package/addon.lua b/xmake/core/package/addon.lua new file mode 100644 index 000000000..d6798f56f --- /dev/null +++ b/xmake/core/package/addon.lua @@ -0,0 +1,826 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file addon.lua +-- + +-- define module +local addon = addon or {} + +-- load modules +local os = require("base/os") +local io = require("base/io") +local path = require("base/path") +local table = require("base/table") +local utils = require("base/utils") +local global = require("base/global") + +-- the payload directories of an addon +-- +-- an addon can provide any subset of them, e.g. only `plugins` +-- +-- @note only `plugins` is activated for now, the others are reserved +-- +function addon._payloaddirs() + return {"plugins", "rules", "toolchains", "platforms", "modules", "templates", "themes", "includes"} +end + +-- the manifest file of an addon, e.g. <sourcedir>/addon.lua +-- +-- an addon describes itself in this file, so its name and layout never depend on +-- the package name of the repository which distributes it +-- +function addon._manifestfile(sourcedir) + return path.join(sourcedir, "addon.lua") +end + +-- the interpreter of the addon manifest +function addon._interpreter() + local interp = addon._INTERPRETER + if interp == nil then + -- we need to load it lazily, the interpreter also depends on this module + local interpreter = require("base/interpreter") + interp = interpreter.new() + interp:api_define(addon.apis()) + addon._INTERPRETER = interp + end + return interp +end + +-- the registry file of the installed addons, e.g. ~/.xmake/addons/addons.conf +-- +-- we save all installed addons to this file when installing/removing them, +-- so we do not need to scan the whole addons directory on startup +-- +function addon._registryfile() + return path.join(addon.installdir(), "addons.conf") +end + +-- save the given registry to the registry file +function addon._save(registry) + addon._REGISTRY = registry + addon._ADDONS = nil + local registryfile = addon._registryfile() + -- we need not create an empty registry file if no addons are installed + if table.empty(registry) and not os.isfile(registryfile) then + return + end + local ok, errors = io.save(registryfile, registry) + if not ok then + utils.warning(errors) + end +end + +-- get the payload directory of the given addon +-- +-- @param name the addon name, e.g. "esp32" +-- @param kind the payload kind, e.g. "rules", "modules" +-- @return the directory, e.g. ~/.xmake/addons/esp32/v1.0.0/rules +-- +function addon._payloaddir(name, kind) + local dirname = addon.dirname(name) + local addoninfo = addon.addons()[dirname] + if addoninfo and table.contains(addoninfo.payloads or {}, kind) then + return path.join(addon.installdir(), dirname, addoninfo.version, kind) + end +end + +-- get the plugin task names of the given addon directory +-- +-- the plugins are not namespaced, we need them to check the conflicts +-- +function addon._plugins_of(addondir) + local plugins = {} + for _, filepath in ipairs(os.files(path.join(addondir, "plugins", "*", "xmake.lua"))) do + local content = io.readfile(filepath) + if content then + for taskname in content:gmatch("task%s*%(%s*\"(.-)\"") do + table.insert(plugins, taskname) + end + end + end + return plugins +end + +-- get the template ids of the given addon directory, e.g. {"c/console"} +-- +-- the templates are not namespaced, we need them to check the conflicts +-- +function addon._templates_of(addondir) + local templates = {} + local templatesdir = path.join(addondir, "templates") + for _, langdir in ipairs(os.dirs(path.join(templatesdir, "*"))) do + local lang = path.filename(langdir) + local accepted = {} + for _, filepath in ipairs(os.files(path.join(langdir, "**", "xmake.lua"))) do + local dir = path.directory(filepath) + local relpath = path.relative(dir, langdir) + if relpath and relpath ~= "." then + local nested = false + for _, root in ipairs(accepted) do + if dir:startswith(root .. path.sep()) then + nested = true + break + end + end + if not nested then + table.insert(accepted, dir) + table.insert(templates, lang .. "/" .. (relpath:gsub("[/\\]", "."))) + end + end + end + end + return templates +end + +-- check the conflicts of the plugins and templates, they are not namespaced +-- +-- @param dirname the addon directory name +-- @param addoninfo the addon information, @see addon.register +-- +-- @return the errors if there are some conflicts +-- +function addon._check_conflicts(dirname, addoninfo) + local kindnames = {plugins = "plugin", templates = "template", globalmodules = "global module"} + for _, kind in ipairs({"plugins", "templates", "globalmodules"}) do + for _, name in ipairs(addoninfo[kind] or {}) do + for otherdirname, otheraddoninfo in pairs(addon.addons()) do + if otherdirname ~= dirname and table.contains(otheraddoninfo[kind] or {}, name) then + return string.format("%s(%s) conflicts, it has been provided by the addon(%s)!\nplease remove one of them, e.g. xmake addon --remove %s", + kindnames[kind], name, otherdirname, otherdirname) + end + end + end + end + + -- the global modules can also conflict with the builtin and the user modules + -- + -- @note the `core.*` modules are in the core directory of the sandbox, + -- they are not in `<programdir>/modules`, + -- @see core/sandbox/modules/import/core/sandbox/module.lua + local moduledirs = {path.join(os.programdir(), "modules"), + path.join(os.programdir(), "core", "sandbox", "modules", "import"), + path.join(global.directory(), "modules")} + for _, name in ipairs(addoninfo.globalmodules or {}) do + local modulepath = (name:gsub("%.", "/")) .. ".lua" + for _, moduledir in ipairs(moduledirs) do + if os.isfile(path.join(moduledir, modulepath)) then + return string.format("global module(%s) conflicts, it has been provided by %s!\nplease rename it in the addon manifest.", + name, moduledir:startswith(os.programdir()) and "xmake" or moduledir) + end + end + end +end + +-- get the addons which depend on the given addon +function addon._parents(name) + local dirname = addon.dirname(name) + local parents + for otherdirname, entry in table.orderpairs(addon._registry()) do + if otherdirname ~= dirname then + for _, addoninfo in pairs(entry.versions or {}) do + if table.contains(addoninfo.deps or {}, dirname) then + parents = parents or {} + table.insert(parents, otherdirname) + break + end + end + end + end + return parents +end + +-- unregister the given addon or only one of its versions +function addon.unregister(name, version) + local dirname = addon.dirname(name) + local registry = addon._registry() + local entry = registry[dirname] + if entry == nil then + return + end + if version then + entry.versions[version] = nil + if entry.active == version then + -- we need to select the other one deterministically + entry.active = addon.versions(name)[1] + end + if table.empty(entry.versions) then + registry[dirname] = nil + end + else + registry[dirname] = nil + end + addon._save(registry) +end + +-- get the apis of the addon manifest +function addon.apis() + return { + values = { + -- addon.set_xxx + "addon.set_description" + , "addon.set_homepage" + , "addon.set_license" + , "addon.set_sourcedir" + -- addon.add_xxx + , "addon.add_deps" + , "addon.add_globalmodules" + } + } +end + +-- get the manifest of the given addon directory +-- +-- @param sourcedir the addon source or install directory, which contains `addon.lua` +-- +-- @return the manifest, e.g. {name = "esp32-devel", description = "...", sourcedir = "src", deps = {"serial-tools"}} +-- it will be nil if this addon does not describe itself +-- +function addon.manifest(sourcedir) + + -- we may resolve a lot of `@self` references, so we need to cache them + local manifests = addon._MANIFESTS + if manifests == nil then + manifests = {} + addon._MANIFESTS = manifests + end + local cachekey = path.absolute(sourcedir) + local cacheinfo = manifests[cachekey] + if cacheinfo ~= nil then + return cacheinfo or nil + end + + local manifestfile = addon._manifestfile(sourcedir) + if not os.isfile(manifestfile) then + manifests[cachekey] = false + return + end + local interp = addon._interpreter() + local ok, errors = interp:load(manifestfile) + if not ok then + return nil, errors + end + local results, errors = interp:make("addon", true, true) + if not results then + return nil, errors + end + local manifest + for name, addoninfo in pairs(results) do + if manifest then + return nil, string.format("%s: only one addon() scope is allowed!", manifestfile) + end + manifest = {name = name, + description = addoninfo:get("description"), + homepage = addoninfo:get("homepage"), + license = addoninfo:get("license"), + sourcedir = addoninfo:get("sourcedir"), + deps = table.wrap(addoninfo:get("deps")), + globalmodules = table.wrap(addoninfo:get("globalmodules"))} + end + if not manifest then + return nil, string.format("%s: no addon() scope found!", manifestfile) + end + manifests[cachekey] = manifest + return manifest +end + +-- get a working directory which has no project +-- +-- we need it to run the sub-processes of the addons, e.g. `xrepo install --addon`, +-- otherwise they would load the project of the current directory again +-- +-- @note we cannot use `os.tmpdir()` directly, it is shared by all the commands, +-- e.g. a stray `xmake.lua` in it would break the isolation +-- +-- @note we can share it between the processes, we only use it as the working directory +-- and never write anything into it, @see private/action/addon/impl/xrepo.lua +-- +function addon.workdir() + local workdir = path.join(os.tmpdir(), "addons", "working") + if not os.isdir(workdir) then + -- it may be created by the other processes at the same time, we can ignore it + os.mkdir(workdir) + end + return workdir +end + +-- the install directory of addons, e.g. ~/.xmake/addons +function addon.installdir() + return path.join(global.directory(), "addons") +end + +-- get the directory name of the given addon name, e.g. "myns::foo" -> "myns_foo" +function addon.dirname(name) + return (name:lower():gsub("::", "_")) +end + +-- is the given reference an addon reference? +-- +-- e.g. "@addon/esp32/flash", "@self/flash", "@addon.esp32.sdkconfig", "@self.sdkconfig" +-- +function addon.is_reference(reference, sep) + return reference:startswith("@addon" .. sep) or reference:startswith("@self" .. sep) +end + +-- get the addon which owns the given script directory +-- +-- it's used to resolve the `@self` references inside an addon, +-- so that the addon code never needs to know its own installed name +-- +-- @param scriptdir the script directory, e.g. ~/.xmake/addons/esp32/v1.0.0/rules/flash +-- it will be the directory of the caller script by default +-- @return the addon name and its root directory, e.g. esp32, ~/.xmake/addons/esp32/v1.0.0 +-- +function addon.owner(scriptdir) + if not scriptdir then + -- we can get it from the sandbox of the caller script, e.g. the rule script of an addon + local sandbox = require("sandbox/sandbox") + local instance = sandbox.instance() + scriptdir = instance and instance:rootdir() + end + if not scriptdir then + return + end + scriptdir = path.absolute(scriptdir) + + -- the installed addons, e.g. ~/.xmake/addons/<name>/<version>/... + local installdir = path.absolute(addon.installdir()) + if scriptdir:startswith(installdir .. path.sep()) then + local parts = path.split(path.relative(scriptdir, installdir)) + if #parts >= 2 then + local addondir = path.join(installdir, parts[1], parts[2]) + -- the registry keeps the raw addon name, the directory name is only + -- its normalized form, e.g. "myns::foo" -> "myns_foo" + local addoninfo = addon.addons()[parts[1]] + return addoninfo and addoninfo.name or parts[1], addondir + end + return + end + + -- the addon source directory, we can also run the addon code in place when developing it + local dir = scriptdir + while dir and #dir > 0 do + -- the addon describes itself? we get its name from the manifest + local manifest = addon.manifest(dir) + if manifest then + return manifest.name, dir + end + -- otherwise we can only guess it from the payload directories + for _, payloaddir in ipairs(addon._payloaddirs()) do + if os.isdir(path.join(dir, payloaddir)) then + return path.filename(dir), dir + end + end + local parentdir = path.directory(dir) + if not parentdir or parentdir == dir then + break + end + dir = parentdir + end +end + +-- resolve the given addon reference to its payload directory +-- +-- the addon resources are referenced with the addon name from the outside, +-- and with `@self` from the addon code itself, e.g. +-- +-- add_rules("@addon/esp32/flash"), import("@addon.esp32.sdkconfig") -- from a project +-- add_rules("@self/flash"), import("@self.sdkconfig") -- from the addon itself +-- +-- @param reference the reference, e.g. "@addon/esp32/flash", "@self.sdkconfig" +-- @param sep the separator, e.g. "/", "." +-- @param kind the payload kind, e.g. "rules", "modules" +-- @param opt the options, e.g. {scriptdir = "..."}, it's used to resolve `@self` +-- +-- @return the reference information and errors, +-- e.g. {dir = "~/.xmake/addons/esp32/v1.0.0/rules", name = "flash", addon = "esp32"} +-- +function addon.resolve_reference(reference, sep, kind, opt) + opt = opt or {} + + -- resolve the `@self` reference from the addon which owns the current script + if reference:startswith("@self" .. sep) then + local name = reference:sub(#("@self" .. sep) + 1) + if name == "" then + return nil, string.format("invalid addon reference(%s)!", reference) + end + local addonname, addondir = addon.owner(opt.scriptdir) + if not addondir then + return nil, string.format("%s: cannot resolve `@self`, it can only be used inside an addon!", reference) + end + return {dir = path.join(addondir, kind), name = name, addon = addonname} + end + + -- resolve the `@addon` reference, the addon name is always required + local prefix = "@addon" .. sep + if not reference:startswith(prefix) then + return + end + local pos = reference:find(sep, #prefix + 1, true) + local addonname = pos and reference:sub(#prefix + 1, pos - 1) + local name = pos and reference:sub(pos + 1) + if not addonname or addonname == "" or not name or name == "" then + return nil, string.format("invalid addon reference(%s), it should be `@addon%s<addon>%s<name>`", reference, sep, sep) + end + local payloaddir = addon._payloaddir(addonname, kind) + if not payloaddir then + return nil, string.format("%s not found!\nplease install the addon which provides it first: xmake addon --install %s", reference, addonname) + end + return {dir = payloaddir, name = name, addon = addonname} +end + +-- get the registry of the installed addons +-- +-- an addon can be installed with several versions at the same time, e.g. the projects +-- may lock the different versions of it, so we save all of them +-- +-- @return the registry, e.g. {["esp32"] = {active = "1.0.3", versions = {["1.0.3"] = {...}}}} +-- +function addon._registry(opt) + local registry = addon._REGISTRY + if opt and opt.force then + registry = nil + end + if registry == nil then + registry = {} + local registryfile = addon._registryfile() + if os.isfile(registryfile) then + registry = io.load(registryfile) or {} + end + -- migrate the old registry, it only saved one version for each addon + for dirname, addoninfo in pairs(registry) do + if addoninfo.versions == nil then + registry[dirname] = {active = addoninfo.version, + versions = {[addoninfo.version] = addoninfo}} + end + end + addon._REGISTRY = registry + addon._ADDONS = nil + end + return registry +end + +-- pin the active version of the given addon for this process +-- +-- @note a project locks the versions of its addons, so we need to activate them +-- when we load it, @see core/project/addons.lua +-- +function addon.pin(name, version) + local pinned = addon._PINNED + if pinned == nil then + pinned = {} + addon._PINNED = pinned + end + pinned[addon.dirname(name)] = version + addon._ADDONS = nil +end + +-- get all the installed versions of the given addon, e.g. {"1.0.2", "1.0.3"} +function addon.versions(name) + local addoninfo = addon._registry()[addon.dirname(name)] + return table.orderkeys(addoninfo and addoninfo.versions or {}) +end + +-- get all installed addons, only the active version of each addon +-- +-- @param opt the options, e.g. {force = true}, we need it to reload the registry +-- if the addons have been installed by another process +-- +-- @return the addons table, e.g. {["hello-world"] = {version = "latest", payloads = {"plugins"}}} +-- +function addon.addons(opt) + opt = opt or {} + if opt.force then + addon._registry({force = true}) + end + + -- get the really installed versions instead of the pinned ones? e.g. locking them + -- @note we do not cache it, the cache is the pinned view of this project + if opt.unpinned then + local addons = {} + for dirname, addoninfo in pairs(addon._registry()) do + local versioninfo = addoninfo.versions and addoninfo.versions[addoninfo.active] + if versioninfo then + addons[dirname] = versioninfo + end + end + return addons + end + + local addons = addon._ADDONS + if addons == nil then + addons = {} + local pinned = addon._PINNED or {} + for dirname, addoninfo in pairs(addon._registry()) do + -- the project may lock another version of it, @see addon.pin + local version = pinned[dirname] or addoninfo.active + local versioninfo = addoninfo.versions and addoninfo.versions[version] + if versioninfo then + addons[dirname] = versioninfo + end + end + addon._ADDONS = addons + end + return addons +end + +-- get the install directory of the given addon, e.g. ~/.xmake/addons/<name>/<version> +function addon.addondir(name, version) + local dirname = addon.dirname(name) + if version == nil then + local addoninfo = addon.addons()[dirname] + if addoninfo == nil then + return nil + end + version = addoninfo.version + end + return path.join(addon.installdir(), dirname, version) +end + +-- get the modules which the installed addons export as the global modules +-- +-- they are declared in the addon manifest, e.g. add_globalmodules("core.tools.esptool"), +-- so that they can be imported with their plain names by the internal calls, +-- e.g. import("core.tools.esptool"), find_tool("esptool") +-- +-- @return the modules table, e.g. {["core.tools.esptool"] = "~/.xmake/addons/esp32/v1.0.0/modules"} +-- +function addon.globalmodules() + local globalmodules = addon._GLOBALMODULES + if globalmodules == nil then + globalmodules = {} + for dirname, addoninfo in pairs(addon.addons()) do + for _, name in ipairs(addoninfo.globalmodules or {}) do + globalmodules[name] = path.join(addon.installdir(), dirname, addoninfo.version, "modules") + end + end + addon._GLOBALMODULES = globalmodules + end + return globalmodules +end + +-- find the include files of the given addon reference, e.g. includes("@addon/esp32/board") +-- +-- @param interp the interpreter which is loading the file, @see interpreter:includes_resolver_add +-- @param reference the reference, e.g. "@addon/esp32/board", "@self/board" +-- +-- @return the files, or nil and errors +-- +function addon.find_includes(interp, reference) + if not addon.is_reference(reference, "/") then + return + end + local referenceinfo, errors = addon.resolve_reference(reference, "/", "includes", {scriptdir = interp:scriptdir()}) + if not referenceinfo then + return nil, errors + end + local name = referenceinfo.name + local files + if name:endswith(".lua") then + files = os.files(path.join(referenceinfo.dir, name)) + else + files = os.files(path.join(referenceinfo.dir, name, "xmake.lua")) + end + + -- the addon is installed, but it does not provide this file, we cannot ignore it + if not files or #files == 0 then + os.raise("includes(%s) not found!", reference) + end + return files +end + +-- get the payload directories of the given kind from all installed addons +-- +-- @param kind the payload kind, e.g. "plugins", "rules" +-- @return the directories, e.g. {"~/.xmake/addons/hello-world/latest/plugins"} +-- +-- @note we do not check if these directories exist, the callers will just ignore the invalid ones +-- +function addon.payloads(kind) + local payloads = {} + for _, payloadinfo in ipairs(addon.payloadinfos(kind)) do + table.insert(payloads, payloadinfo.dir) + end + return payloads +end + +-- get the payload information of the given kind from all installed addons +-- +-- @param kind the payload kind, e.g. "plugins", "rules" +-- @return the payload infos, e.g. {{name = "hello-world", version = "latest", dir = "~/.xmake/addons/hello-world/latest/plugins"}} +-- +function addon.payloadinfos(kind) + local payloadinfos = {} + for name, addoninfo in table.orderpairs(addon.addons()) do + if table.contains(addoninfo.payloads or {}, kind) then + table.insert(payloadinfos, { + name = name, + version = addoninfo.version, + dir = path.join(addon.installdir(), name, addoninfo.version, kind)}) + end + end + return payloadinfos +end + +-- get the payload root directory of the given addon source directory +-- +-- an addon repository has its own files, e.g. tests, ci scripts and documents, +-- so its payloads can be placed in the `src` subdirectory, and we only install them +-- +-- e.g. +-- esp32-devel/src/{plugins,rules,toolchains,templates} -- with the `src` layout +-- hello-world/{plugins} -- without it, for the simple addons +-- +-- @param sourcedir the addon source directory +-- @return the payload root directory, it will be nil if no payload is found +-- +function addon.payloadroot(sourcedir) + + -- the addon can set its payload root directory explicitly, e.g. set_sourcedir("src") + local manifest = addon.manifest(sourcedir) + if manifest and manifest.sourcedir then + local payloadroot = path.join(sourcedir, manifest.sourcedir) + if #addon.payloads_of(payloadroot) > 0 then + return payloadroot + end + return + end + + local srcdir = path.join(sourcedir, "src") + if #addon.payloads_of(srcdir) > 0 then + return srcdir + end + if #addon.payloads_of(sourcedir) > 0 then + return sourcedir + end +end + +-- get the payload directories of the given addon directory, e.g. {"plugins", "rules"} +function addon.payloads_of(addondir) + local payloads = {} + for _, payloaddir in ipairs(addon._payloaddirs()) do + if os.isdir(path.join(addondir, payloaddir)) then + table.insert(payloads, payloaddir) + end + end + return payloads +end + +-- get the default on_install script of addon packages +-- +-- we only install the payload directories of this addon, e.g. plugins, rules, toolchains, ... +-- +function addon.installscript() + return function (package) + local sourcedir = os.curdir() + + -- the addon name is its identity, e.g. the install directory, the registry key + -- and the `@addon/<name>/xxx` references, so the package must be distributed with the same name + local manifest, errors = addon.manifest(sourcedir) + if errors then + os.raise(errors) + end + if manifest and addon.dirname(manifest.name) ~= addon.dirname(package:name()) then + os.raise("addon(%s) does not match the package name(%s) in the repository!\nplease fix the package recipe or the addon manifest.", + manifest.name, package:name()) + end + + local payloadroot = addon.payloadroot(sourcedir) + if not payloadroot then + os.raise("addon(%s): no payload directory found, e.g. plugins!", package:name()) + end + for _, payloaddir in ipairs(addon.payloads_of(payloadroot)) do + os.cp(path.join(payloadroot, payloaddir), package:installdir()) + end + + -- we need not install the manifest, the package manifest(manifest.txt) and the addons + -- registry already have all the information, we just pass it to the registration + if manifest then + package:data_set("addon.manifest", manifest) + end + end +end + +-- register the given installed addon +-- +-- @param name the addon name +-- @param version the addon version, e.g. "1.0.1", "latest" +-- @param opt the options, e.g. {description = "...", deps = {"foo"}} +-- +-- @note the addon manifest(addon.lua) is only read when installing, everything which +-- is needed later is recorded here, so we never parse it again +-- +-- @return true or false and errors +-- +function addon.register(name, version, opt) + opt = opt or {} + local dirname = addon.dirname(name) + local addondir = path.join(addon.installdir(), dirname, version) + local addoninfo = {version = version, + -- we need to keep the raw name, the directory name is only its + -- normalized form, e.g. "myns::foo" -> "myns_foo" + name = name ~= dirname and name or nil, + description = opt.description, + deps = opt.deps, + -- where it comes from, e.g. {url = ..., commit = ..., branch = ...} + repo = opt.repo, + -- the deps which the addon itself declares in its manifest, they are + -- recorded whenever this addon has one, so that the repositories can + -- check that the manifest and the package recipe are kept in sync + manifest_deps = opt.manifest_deps, + globalmodules = opt.globalmodules, + payloads = addon.payloads_of(addondir), + plugins = addon._plugins_of(addondir), + templates = addon._templates_of(addondir)} + + -- we need to check the conflicts of the plugins and templates first, + -- they are not namespaced and we do not know which one will be used + local errors = addon._check_conflicts(dirname, addoninfo) + if errors then + return false, errors + end + + -- we can install several versions of an addon at the same time, + -- and the version which we install now is always the active one + local registry = addon._registry() + local entry = registry[dirname] + if entry == nil or entry.versions == nil then + entry = {versions = {}} + registry[dirname] = entry + end + entry.versions[version] = addoninfo + entry.active = version + addon._save(registry) + return true +end + +-- remove the given installed addon +-- +-- @param name the addon name +-- @return true or false and errors +-- +function addon.remove(name, opt) + opt = opt or {} + local dirname = addon.dirname(name) + local installdir = path.join(addon.installdir(), dirname) + if not os.isdir(installdir) then + return false, string.format("addon(%s) not found!", name) + end + + -- we cannot remove it if the other addons depend on it + if not opt.force then + local parents = addon._parents(name) + if parents then + return false, string.format("addon(%s) cannot be removed, it's depended on by the addon(%s)!\nplease remove them first, or pass --force to remove it anyway", + name, table.concat(parents, ", ")) + end + end + -- we need to remove the symlinks first, we cannot remove them recursively, + -- otherwise the linked files would be removed too + -- + -- e.g. the user may link the install directory to the addon source directory when developing it + for _, versiondir in ipairs(os.dirs(path.join(installdir, "*"))) do + if os.islink(versiondir) then + os.rmfile(versiondir) + end + end + if os.islink(installdir) then + return os.rmfile(installdir) + end + + local ok, errors = os.rm(installdir) + if not ok then + return false, errors + end + addon.unregister(name) + return true +end + +-- reload the addons registry and the caches which are built from it +-- +-- @note we need it if the addons have been installed by another process, +-- e.g. the addons which a project declares, @see core/project/project.lua +-- +function addon.reload() + addon._REGISTRY = nil + addon._ADDONS = nil + addon._MANIFESTS = nil + addon._GLOBALMODULES = nil +end + +-- return module +return addon diff --git a/xmake/core/package/component.lua b/xmake/core/package/component.lua index c55dc4a73..bdf1ff061 100644 --- a/xmake/core/package/component.lua +++ b/xmake/core/package/component.lua @@ -135,7 +135,7 @@ function _instance:_load() if not loaded then local script = self:_on_component() if script then - local ok, errors = sandbox.load(script, self:package(), self) + local ok, errors = sandbox.call(script, self:package(), self) if not ok then os.raise("load component(%s) failed, %s", self:name(), errors or "unknown errors") end diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index 0d164ce95..3d98a3743 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -37,6 +37,7 @@ local interpreter = require("base/interpreter") local select_script = require("base/private/select_script") local is_cross = require("base/private/is_cross") local memcache = require("cache/memcache") +local addon = require("package/addon") local toolchain = require("tool/toolchain") local compiler = require("tool/compiler") local linker = require("tool/linker") @@ -54,6 +55,16 @@ local sandbox_os = require("sandbox/modules/os") local sandbox_module = require("sandbox/modules/import/core/sandbox/module") -- new an instance +-- +-- @param name the package name, the namespace prefix will be stripped and saved separately, +-- e.g. "zlib", "myns::zlib", but "vcpkg::zlib" will be kept as a whole, +-- because `vcpkg` is a package manager, but not a namespace +-- @param info the package description scope info +-- @param opt the options +-- - scriptdir: the directory of the package description file, the relative paths in +-- this package will be relative to it +-- - repo: the repository instance which this package belongs to +-- function _instance.new(name, info, opt) opt = opt or {} local instance = table.inherit(_instance) @@ -610,6 +621,23 @@ function _instance:is_toolchain() return self:kind() == "toolchain" end +-- is addon package? +-- +-- it will be installed to `~/.xmake/addons/<name>/<version>` and +-- it can provide plugins, rules, toolchains, templates and modules for xmake +-- +function _instance:is_addon() + return self:kind() == "addon" +end + +-- is plugin package? +-- +-- @note this kind is deprecated, please use the `addon` kind instead +-- +function _instance:is_plugin() + return self:kind() == "plugin" +end + -- is library package? -- -- @return true if the package kind is "library" or default @@ -907,20 +935,32 @@ function _instance:installdir(...) installdir = self:get("installdir") if not installdir then local name = self:name():lower():gsub("::", "_") - if self:is_local() then - installdir = path.join(package.installdir({localdir = true}), name:sub(1, 1):lower(), name) - else - installdir = path.join(package.installdir(), name:sub(1, 1):lower(), name) - end - local version_str = self:version_str() - if version_str then - -- strip invalid characters on windows, e.g. `>= <=` + if self:is_addon() then + -- e.g. ~/.xmake/addons/<name>/<version> + local version_str = self:version_str() or "latest" if os.is_host("windows") then version_str = version_str:gsub("[>=<|%*]", "") end - installdir = path.join(installdir, version_str) + installdir = addon.addondir(self:name(), version_str) + elseif self:is_plugin() then + -- deprecated, @see the `addon` kind + installdir = path.join(global.directory(), "plugins", name) + else + if self:is_local() then + installdir = path.join(package.installdir({localdir = true}), name:sub(1, 1):lower(), name) + else + installdir = path.join(package.installdir(), name:sub(1, 1):lower(), name) + end + local version_str = self:version_str() + if version_str then + -- strip invalid characters on windows, e.g. `>= <=` + if os.is_host("windows") then + version_str = version_str:gsub("[>=<|%*]", "") + end + installdir = path.join(installdir, version_str) + end + installdir = path.join(installdir, self:buildhash()) end - installdir = path.join(installdir, self:buildhash()) end self._INSTALLDIR = installdir end @@ -1136,7 +1176,7 @@ function _instance:_load() if on_load then on_load(self) end - + -- load all components self:_load_components() @@ -1174,6 +1214,7 @@ function _instance:_rawenvs() envs.DYLD_LIBRARY_PATH = {"lib"} end end + self._RAWENVS = envs end return envs @@ -2076,11 +2117,17 @@ function _instance:fetch(opt) -- always install to the local project directory? -- @see https://github.com/xmake-io/xmake/pull/4376 + -- + -- @note the host packages are the tools which build the other packages, e.g. the toolchains, + -- they do not depend on the project configuration and they are shared between the projects, + -- so they are only installed locally with their own policy + -- @see https://github.com/xmake-io/xmake/issues/7716 + local policyname = self:is_host() and "package.host.install_locally" or "package.install_locally" local install_locally - if project and project.policy("package.install_locally") then + if project and project.policy(policyname) then install_locally = true end - if install_locally == nil and self:policy("package.install_locally") then + if install_locally == nil and self:policy(policyname) then install_locally = true end if not self:is_local() and install_locally and system ~= true then @@ -2488,9 +2535,20 @@ function _instance:_generate_runtime_configs(sourcekind) self.sourcekinds = function (self) return sourcekind end - configs.cxflags = self:compiler(sourcekind):map_flags("runtime", runtimes, {target = self}) - configs.ldflags = self:linker("binary", sourcekind):map_flags("runtime", runtimes, {target = self}) - configs.shflags = self:linker("shared", sourcekind):map_flags("runtime", runtimes, {target = self}) + local cxflags = self:compiler(sourcekind):map_flags("runtime", runtimes, {target = self}) + local ldflags = self:linker("binary", sourcekind):map_flags("runtime", runtimes, {target = self}) + local shflags = self:linker("shared", sourcekind):map_flags("runtime", runtimes, {target = self}) + + -- @note the multi-argument flags must be checked as a whole, e.g. the clang runtime + -- flags on windows, `-Xclang --dependent-lib=xxx` would be broken if + -- `--dependent-lib=xxx` is checked and dropped separately + -- @see https://github.com/xmake-io/xmake/issues/7704 + local group = function (flags) + return flags and #flags > 1 and {table.wrap_lock(flags)} or flags + end + configs.cxflags = group(cxflags) + configs.ldflags = group(ldflags) + configs.shflags = group(shflags) self.sourcekinds = nil end return configs @@ -2556,6 +2614,79 @@ function _instance:_generate_build_configs(configs, opt) return configs end +-- has the given payloads? (only for the addon packages) +-- +-- @param opt the payloads to be checked, the value can be a string or a list, e.g. +-- {rules = "app", toolchains = "esp32", plugins = "monitor", +-- templates = "c/esp32.hello", modules = {"private.board", "private.flasher"}} +-- +-- @return true, or false and errors +-- +-- e.g. +-- +-- on_test(function (package) +-- assert(package:has_addon({rules = "app", toolchains = "esp32"})) +-- end) +-- +function _instance:has_addon(opt) + if not self:is_addon() then + return false, string.format("package(%s) is not an addon!", self:name()) + end + + -- the addon should be registered after installing it + local addoninfo = addon.addons()[addon.dirname(self:name())] + if not addoninfo then + return false, string.format("addon(%s) is not installed!", self:name()) + end + if opt == nil then + return true + end + + local checkers = {} + + -- the rules are namespaced, e.g. @addon/esp32-devel/app + -- + -- @note we need to reload the global rules, this addon may be installed just now + checkers.rules = function (name) + local rule = require("project/rule") + rule.clear() + return rule.rules()["@addon/" .. self:name() .. "/" .. name] ~= nil + end + + -- the toolchains are namespaced too, e.g. @addon/esp32-devel/esp32 + checkers.toolchains = function (name) + return toolchain.load("@addon/" .. self:name() .. "/" .. name) ~= nil + end + + -- the plugins and the templates are not namespaced, we get them from the addons registry, + -- the task list of this process has been loaded before installing this addon + checkers.plugins = function (name) + return table.contains(addoninfo.plugins or {}, name) + end + checkers.templates = function (name) + return table.contains(addoninfo.templates or {}, name) + end + + -- the modules are files, e.g. modules/serial.lua, modules/private/board.lua + checkers.modules = function (name) + local modulepath = path.join(self:installdir(), "modules", (name:gsub("%.", "/"))) + return os.isfile(modulepath .. ".lua") or os.isdir(modulepath) + end + + for kind, names in pairs(opt) do + local checker = checkers[kind] + if not checker then + return false, string.format("unknown addon payload(%s), it should be one of rules, toolchains, plugins, templates and modules!", kind) + end + for _, name in ipairs(table.wrap(names)) do + if not checker(name) then + return false, string.format("%s(%s) not found in the addon(%s)!", kind, name, self:name()) + end + end + end + return true +end + -- has the given c funcs? -- -- @param funcs the funcs @@ -2985,12 +3116,20 @@ end -- -- @param opt the options, e.g. {localdir = true} -- - localdir: return the local project packages directory (build/.packages) --- instead of the global directory (~/.xmake/packages) +-- instead of the global directory (~/.xmake/packages), +-- it can be overridden with `XMAKE_PKG_LOCALDIR` -- -- @return the install directory path -- function package.installdir(opt) if opt and opt.localdir then + -- the parent process passes its local directory to the sub-process which builds + -- a package, so the packages it installs locally land in the same place and are + -- not installed twice, @see https://github.com/xmake-io/xmake/issues/7716 + local localdir = os.getenv("XMAKE_PKG_LOCALDIR") + if localdir then + return path.normalize(path.absolute(localdir)) + end return path.join(config.builddir({absolute = true}), ".packages") end local installdir = package._INSTALLDIR @@ -3015,6 +3154,14 @@ function package.searchdirs() end -- load the package from the system directories +-- +-- it will be used for `add_requires("zlib", {system = true})` and the 3rd package managers, +-- e.g. add_requires("vcpkg::zlib"), add_requires("conan::zlib/1.2.11") +-- +-- @param packagename the package name, e.g. "zlib", "vcpkg::zlib", "xmake::zlib" +-- +-- @return the package instance and errors +-- function package.load_from_system(packagename) -- get package info @@ -3083,6 +3230,15 @@ function package.load_from_system(packagename) end -- load the package from the project file +-- +-- it will load the package which is defined by `package()` in the project xmake.lua, +-- and we will also try to find it from the project namespaces if it's not found directly +-- +-- @param packagename the package name, e.g. "zlib", it can be without the namespace prefix +-- @param project the project module, we need to pass it to avoid the cyclic imports +-- +-- @return the package instance and errors, it will be nil if this package is not defined in the project +-- function package.load_from_project(packagename, project) -- load packages (with cache) @@ -3111,8 +3267,20 @@ function package.load_from_project(packagename, project) end -- load the package from the package directory or package description file +-- +-- @param packagename the package name, e.g. "zlib" +-- @param packagedir the package directory, we will load `packagedir/xmake.lua`, it can be nil if `opt.packagefile` is set +-- @param opt the options +-- - packagefile: load the package from the given description file directly instead of `packagedir/xmake.lua` +-- - plat: the given platform, we need to set it to the description scope at same time, +-- e.g. add_requires("zlib~mingw", {plat = "mingw"}) +-- @see https://github.com/orgs/xmake-io/discussions/3439 +-- - arch: the given architecture, it's the same as `opt.plat` +-- - repo: the repository instance which this package belongs to +-- +-- @return the package instance and errors +-- function package.load_from_repository(packagename, packagedir, opt) - opt = opt or {} -- find the package script path @@ -3173,6 +3341,21 @@ function package.load_from_repository(packagename, packagedir, opt) return nil, string.format("%s: package(%s) not found!", scriptpath, packagename) end + -- we need set the default on_install script if it's addon package + if packageinfo:get("kind") == "addon" and not packageinfo:get("install") then + packageinfo:set("install", addon.installscript()) + end + + -- we need set the default on_install script if it's plugin package + -- @note the plugin kind is deprecated, please use the addon kind instead + if packageinfo:get("kind") == "plugin" and not packageinfo:get("install") then + -- only one code line, we can directly omit the sandbox wrapper. + local on_install = function (pkg) + os.cp("*", pkg:installdir()) + end + packageinfo:set("install", on_install) + end + package._memcache():set2("packageinfos.repository", cachekey, packageinfo) end diff --git a/xmake/core/platform/menu.lua b/xmake/core/platform/menu.lua index cec901ee8..77a57381d 100644 --- a/xmake/core/platform/menu.lua +++ b/xmake/core/platform/menu.lua @@ -42,7 +42,7 @@ function _remote_build_is_connected() local projectdir = os.projectdir() local projectfile = os.projectfile() if projectfile and os.isfile(projectfile) and projectdir then - local workdir = path.join(config.directory(), "remote_build") + local workdir = path.join(config.directory(), "service", "remote_build") local statusfile = path.join(workdir, "status.txt") if os.isfile(statusfile) then local status = io.load(statusfile) diff --git a/xmake/core/platform/platform.lua b/xmake/core/platform/platform.lua index f5eb9ab94..cd6c7722e 100644 --- a/xmake/core/platform/platform.lua +++ b/xmake/core/platform/platform.lua @@ -109,7 +109,7 @@ function _instance:get(name) if not self._LOADED and not self:_is_builtin_conf(name) then local on_load = self._INFO:get("load") if on_load then - local ok, errors = sandbox.load(on_load, self) + local ok, errors = sandbox.call(on_load, self) if not ok then os.raise(errors) end diff --git a/xmake/core/project/addons.lua b/xmake/core/project/addons.lua new file mode 100644 index 000000000..c979a6f8d --- /dev/null +++ b/xmake/core/project/addons.lua @@ -0,0 +1,140 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file addons.lua +-- + +-- define module +local addons = addons or {} + +-- load modules +local os = require("base/os") +local io = require("base/io") +local path = require("base/path") +local table = require("base/table") +local semver = require("base/semver") +local addon = require("package/addon") + +-- the lock file of the declared addons, e.g. <projectdir>/xmake-addons.lock +-- +-- @note it's independent of `xmake-requires.lock`, the addons are always locked, +-- they provide the build scripts and we should never change them silently +-- +function addons.lockfile(projectdir) + return path.join(projectdir or os.projectdir(), "xmake-addons.lock") +end + +-- get the format version of the addons lock file +-- +-- @see xmake/core/project/project.lua, project.requireslock_version() +-- +function addons.lockfile_version() + return "1.0" +end + +-- check the addons which a project declares, e.g. add_addons("esp32-devel 1.0.x") +-- +-- @return true, or false and errors +-- +function addons.validate(requires) + local declared = {} + for _, requirestr in ipairs(requires) do + local name = addons.requirename(requirestr) + if name == "addon" or name == "self" then + return false, string.format("add_addons(%s): the name is reserved by xmake for the addon references, please rename it!", name) + end + if name == "." or name == ".." or name:find("[/\\:]") then + return false, string.format("add_addons(%s): invalid addon name!", name) + end + + -- we can only install one version of an addon for a project + if declared[name] then + return false, string.format("add_addons(%s): it is declared twice, e.g. `%s` and `%s`, please merge them!", + name, declared[name], requirestr) + end + declared[name] = requirestr + end + return true +end + +-- split the given declaration into the name and the version range +-- +-- @note the version range can contain spaces, so everything after the name belongs to it, +-- e.g. "esp32-devel 1.0.x", "esp32-devel >=1.0 <2.0", "esp32-devel master || >1.4", +-- @see xmake/modules/private/utils/package.lua +-- +function addons.requirename(requirestr) + local splitinfo = requirestr:split("%s+", {limit = 2}) + return splitinfo[1], splitinfo[2] +end + +-- is the locked version still valid for the given declaration? +-- +-- @note the declaration is authoritative, the lock only pins a version inside it, +-- so we need to resolve it again if the user has changed the declared version +-- +function addons.locked_valid(requirestr, lockinfo) + if not lockinfo or not lockinfo.version then + return false + end + local _, range = addons.requirename(requirestr) + if range then + -- @note we can only compare the semantic versions, e.g. the local addons are always `latest` + return semver.is_valid(lockinfo.version) and semver.satisfies(lockinfo.version, range) + end + return true +end + +-- get the locked addons, e.g. {["esp32-devel"] = {version = "1.0.3"}} +function addons.locked(projectdir) + local lockfile = addons.lockfile(projectdir) + if os.isfile(lockfile) then + local lockinfo = io.load(lockfile) + if lockinfo then + lockinfo.__meta__ = nil + return lockinfo + end + end +end + +-- are all the declared addons installed already? +-- +-- @note we need to check it in-process for every command which loads the project, +-- so we only check the locked versions here, the installer will resolve them again +-- +function addons.satisfied(requires, projectdir) + local locked = addons.locked(projectdir) + if not locked then + return false + end + local installed = addon.addons() + for _, requirestr in ipairs(requires) do + local name = addons.requirename(requirestr) + local lockinfo = locked[name] + if not addons.locked_valid(requirestr, lockinfo) then + return false + end + local addoninfo = installed[addon.dirname(name)] + if not addoninfo or addoninfo.version ~= lockinfo.version then + return false + end + end + return true +end + +-- return module +return addons diff --git a/xmake/core/project/option.lua b/xmake/core/project/option.lua index 62687a106..43ba10f05 100644 --- a/xmake/core/project/option.lua +++ b/xmake/core/project/option.lua @@ -142,7 +142,7 @@ function _instance:_do_check_cxsnippets(snippets) -- check snippets (run with output) if #table.keys(snippets_output) > 0 then - local ok, results_or_errors, output = sandbox.load(self._check_cxsnippets, snippets_output, { + local ok, results_or_errors, output = sandbox.call(self._check_cxsnippets, snippets_output, { target = self, sourcekind = sourcekind, types = types, @@ -165,7 +165,7 @@ function _instance:_do_check_cxsnippets(snippets) -- check snippets (run only) if passed == 0 and #table.keys(snippets_tryrun) > 0 then - local ok, results_or_errors = sandbox.load(self._check_cxsnippets, snippets_tryrun, { + local ok, results_or_errors = sandbox.call(self._check_cxsnippets, snippets_tryrun, { target = self, sourcekind = sourcekind, types = types, @@ -187,7 +187,7 @@ function _instance:_do_check_cxsnippets(snippets) -- check snippets (run with binary_match) if #table.keys(snippets_binary_match) > 0 then - local ok, results_or_errors, output = sandbox.load(self._check_cxsnippets, snippets_binary_match, { + local ok, results_or_errors, output = sandbox.call(self._check_cxsnippets, snippets_binary_match, { target = self, sourcekind = sourcekind, types = types, @@ -209,7 +209,7 @@ function _instance:_do_check_cxsnippets(snippets) -- check snippets (build only) if passed == 0 or #table.keys(snippets_build) > 0 then - local ok, results_or_errors = sandbox.load(self._check_cxsnippets, snippets_build, { + local ok, results_or_errors = sandbox.call(self._check_cxsnippets, snippets_build, { target = self, sourcekind = sourcekind, types = types, @@ -296,7 +296,7 @@ function _instance:_on_check() -- get check script local check = self:script("check") if check then - return sandbox.load(check, self) + return sandbox.call(check, self) else return self:_do_check() end diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua index 617a792d6..81a8b6924 100644 --- a/xmake/core/project/policy.lua +++ b/xmake/core/project/policy.lua @@ -158,6 +158,12 @@ function policy.policies() ["package.install_always"] = {description = "Always install packages every time.", type = "boolean"}, -- Install packages in the local project folder ["package.install_locally"] = {description = "Install packages in the local project folder.", default = false, type = "boolean"}, + -- Install the host packages in the local project folder + -- + -- the host packages are the tools which build the other packages, e.g. the toolchains, + -- they do not depend on the project configuration and they are shared between the projects, + -- so they have their own policy, @see https://github.com/xmake-io/xmake/issues/7716 + ["package.host.install_locally"] = {description = "Install the host packages in the local project folder.", default = false, type = "boolean"}, -- Keep package source code after installing (disable source dir cleanup) ["package.keep_source"] = {description = "Keep package source code after installing.", default = false, type = "boolean"}, -- Set custom headers when downloading package diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua index d1030f130..b92c5cfab 100644 --- a/xmake/core/project/project.lua +++ b/xmake/core/project/project.lua @@ -45,6 +45,8 @@ local option = require("project/option") local policy = require("project/policy") local project_package = require("project/package") local deprecated_project = require("project/deprecated/project") +local addon = require("package/addon") +local addons = require("project/addons") local package = require("package/package") local platform = require("platform/platform") local toolchain = require("tool/toolchain") @@ -227,11 +229,131 @@ function project._api_add_toolchaindirs(interp, ...) end end +-- install the addons which this project declares +-- +-- @note we cannot install them here, we are loading the project, so we do it in a +-- sub-process, @see xmake/modules/private/action/addon/impl/install_addons.lua +-- +function project._install_addons(rootinfo) + -- @note we need to cache the result, the project may be loaded many times, + -- otherwise the failure would be ignored by the next load + local result = project._ADDONS_RESULT + if result == nil then + result = project._do_install_addons(rootinfo) + project._ADDONS_RESULT = result + end + return result +end + +-- activate the addon versions which this project locks +-- +-- @note an addon can be installed with several versions at the same time, the other +-- projects may lock the other versions of it, @see core/package/addon.lua +-- +function project._pin_addons() + for name, lockinfo in pairs(addons.locked() or {}) do + -- @note we can only pin an installed version, otherwise this addon would be + -- invisible and every reference to it would just say `not found` + -- + -- the locked version is installed by the auto-fetch, @see addons.satisfied() + -- + if lockinfo.version and table.contains(addon.versions(name), lockinfo.version) then + addon.pin(name, lockinfo.version) + end + end +end + +-- do install the addons which this project declares +-- install the addons which this project declares, e.g. add_addons("esp32-devel 1.0.x") +-- +-- @return the result, e.g. {ok = true, installed = true}, {ok = false, errors = ".."} +-- +function project._do_install_addons(rootinfo) + + -- this project declares nothing? + local requires = table.wrap(rootinfo:get("addons")) + if #requires == 0 then + return {ok = true} + end + local ok, errors = addons.validate(requires) + if not ok then + return {ok = false, errors = errors} + end + + -- they have been installed already? + if addons.satisfied(requires) then + return {ok = true} + end + + -- tell the user why we are installing something, it may need to confirm and download, + -- e.g. `xmake --help` in a project directory which declares some addons + utils.cprint("${color.warning}note: ${clear}this project needs the addons(${bright}%s${clear}), installing them ..", + table.concat(requires, ", ")) + if baseoption.get("help") then + -- the help menu also shows the options which the addons provide, but the user + -- did not ask for an installation, so we tell them how to skip it + utils.cprint("${dim}we can run it outside of the project directory to skip the installation${clear}") + end + + -- we pass the declarations to the installer, it must not load this project again, + -- @see xmake/modules/private/action/addon/impl/install_addons.lua + local datafile = os.tmpfile() + local ok, errors = io.save(datafile, {addons = requires, repositories = table.wrap(rootinfo:get("repositories"))}) + if not ok then + return {ok = false, errors = errors} + end + + -- @note we run it in a working directory which has no project, @see addon.workdir(), + -- otherwise it would load this project again + -- + -- @note we may be called when building the option menu, the command line has not + -- been parsed yet, so we can only get the common flags from the raw arguments + -- + local argv = {"lua"} + local flags = {["-y"] = "--yes", ["--yes"] = "--yes", + ["-v"] = "--verbose", ["--verbose"] = "--verbose", + ["-D"] = "--diagnosis", ["--diagnosis"] = "--diagnosis"} + local flags_added = {} + for _, arg in ipairs(xmake._COMMAND_ARGV or {}) do + local flag = flags[arg] + if flag and not flags_added[flag] then + table.insert(argv, flag) + flags_added[flag] = true + end + end + table.insert(argv, "private.action.addon.impl.install_addons") + table.insert(argv, os.projectdir()) + table.insert(argv, datafile) + local exitcode, errors = os.execv(os.programfile(), argv, {curdir = addon.workdir()}) + os.rm(datafile) + if exitcode ~= 0 then + return {ok = false, errors = errors or "install the addons of this project failed!"} + end + + -- we have loaded the registry and its caches before installing them, so we need to reload it + addon.reload() + project._pin_addons() + rule.clear() + task.clear() + return {ok = true, installed = true} +end + -- load the project file -function project._load(force, disable_filter) +-- +-- @param opt the options +-- - force: load the project file again even if it has been loaded +-- - disable_filter: disable the interpreter filter, e.g. `$(plat)` +-- - skip_addons: do not install the addons which this project declares +-- - addons_installed: the addons have been installed, we are loading it again +-- +function project._load(opt) + opt = opt or {} + + -- use the locked versions of the addons which this project declares + project._pin_addons() -- has already been loaded? - if project._memcache():get("rootinfo") and not force then + if project._memcache():get("rootinfo") and not opt.force then return true end @@ -244,6 +366,12 @@ function project._load(force, disable_filter) -- get interpreter local interp = project.interpreter() + -- this project declares the addons which it needs, e.g. add_addons("esp32-devel"), + -- but we can only know them after loading it, so this pass must survive the references + -- of the addons which are not installed yet, and we load it again after installing them, + -- e.g. includes("@addon/esp32-devel/board") + interp:includes_unresolved_set(not opt.addons_installed) + -- load script local ok, errors = interp:load(project.rootfile(), {on_load_data = function (data) for _, xmakerc_file in ipairs(project.rcfiles()) do @@ -261,13 +389,30 @@ function project._load(force, disable_filter) end -- load the root info of the project - local rootinfo, errors = project._load_scope("root", true, not disable_filter) + local rootinfo, errors = project._load_scope("root", true, not opt.disable_filter) if not rootinfo then return false, errors end + -- install the addons which this project declares, and then load it again with them + -- + -- @note we do not install them for the option menu, it merges the project tasks in a + -- best-effort way and every command builds it, @see project._load_tasks() + -- + if not opt.skip_addons and not opt.addons_installed then + local result = project._install_addons(rootinfo) + if not result.ok then + os.cd(oldir) + return false, result.errors + end + if result.installed then + os.cd(oldir) + return project._load({force = true, disable_filter = opt.disable_filter, addons_installed = true}) + end + end + -- load the root info of the target - local rootinfo_target, errors = project._load_scope("root.target", true, not disable_filter) + local rootinfo_target, errors = project._load_scope("root.target", true, not opt.disable_filter) if not rootinfo_target then return false, errors end @@ -311,6 +456,11 @@ function project._load_scope(scope_kind, deduplicate, enable_filter) end -- load tasks +-- +-- @note we should not install the addons which this project declares here, the option menu +-- merges the project tasks in a best-effort way and every command builds it, +-- e.g. `xmake lua`, `xmake addon --remove --all`, @see xmake/core/main.lua +-- function project._load_tasks() -- the project file is not found? @@ -319,7 +469,7 @@ function project._load_tasks() end -- load the project file first and disable filter - local ok, errors = project._load(true, true) + local ok, errors = project._load({force = true, disable_filter = true, skip_addons = true}) if not ok then return nil, errors end @@ -400,7 +550,7 @@ function project._load_targets() -- load all requires first and reload the project file to ensure has_package() works for targets local requires = project.required_packages() - local ok, errors = project._load(true) + local ok, errors = project._load({force = true}) if not ok then return nil, errors end @@ -481,7 +631,7 @@ function project._load_options(disable_filter) end -- reload the project file to ensure `if is_plat() then add_packagedirs() end` works - local ok, errors = project._load(true, disable_filter) + local ok, errors = project._load({force = true, disable_filter = disable_filter}) if not ok then return nil, errors end @@ -655,6 +805,9 @@ function project.apis() , "add_requires" , "add_requireconfs" , "add_repositories" + -- the addons which this project needs, they are installed automatically, + -- e.g. add_addons("esp32-devel 1.0.x"), @see core/project/addons.lua + , "add_addons" } , paths = { @@ -707,6 +860,10 @@ function project.interpreter() -- set root scope interp:rootscope_set("target") + -- the project file can reference the includes files of the addons, + -- e.g. includes("@addon/esp32-devel/board") + interp:includes_resolver_add(addon.find_includes) + -- define apis for rule interp:api_define(rule.apis()) @@ -1129,7 +1286,7 @@ function project.requires_str() if not requires_str then -- reload the project file to handle `has_config()` - local ok, errors = project._load(true) + local ok, errors = project._load({force = true}) if not ok then os.raise(errors) end @@ -1259,6 +1416,10 @@ end function project.toolchain(name, opt) opt = opt or {} local parseinfo = toolchain.parsename(name) -- we need to ignore `@packagename` + -- the addon toolchains are only loaded from the addons, e.g. set_toolchains("@addon/esp32/xtensa") + if parseinfo.addon_prefix then + return nil + end local toolchain_name = parseinfo.name local info = project._toolchains()[toolchain_name] if info == nil and opt.namespace then diff --git a/xmake/core/project/rule.lua b/xmake/core/project/rule.lua index 332844ca4..5b3b3aa78 100644 --- a/xmake/core/project/rule.lua +++ b/xmake/core/project/rule.lua @@ -31,6 +31,7 @@ local global = require("base/global") local interpreter = require("base/interpreter") local instance_deps = require("base/private/instance_deps") local select_script = require("base/private/select_script") +local addon = require("package/addon") local config = require("project/config") local sandbox = require("sandbox/sandbox") local sandbox_os = require("sandbox/modules/os") @@ -223,6 +224,11 @@ function rule._directories() } end +-- the rule directories of the installed addons, e.g. ~/.xmake/addons/<name>/<version>/rules +function rule._addon_directories() + return addon.payloadinfos("rules") +end + -- the interpreter function rule._interpreter() @@ -453,9 +459,205 @@ function rule.new(name, info, opt) return instance end +-- get the file which declares the given rule, e.g. c.build -> <rulesdir>/c++/xmake.lua +-- +-- most of the rule names match their directory name, so we only need it for the few +-- which do not, e.g. c.build, win.sdk.resource, and we get them by scanning the rule +-- declarations, which is much cheaper than interpreting all the rule files +-- +function rule._rulefile(name) + local rulefiles = rule._RULEFILES + if rulefiles == nil then + + -- @note we only limit the fast paths, a rule file which is nested deeper than this + -- is still found by the full load, @see rule.rules + local maxrecursion = 4 + rulefiles = {} + for _, dir in ipairs(rule._directories()) do + for _, filepath in ipairs(os.files(path.join(dir, "**/xmake.lua"), {recursion = maxrecursion})) do + local content = io.readfile(filepath) + if content then + for rulename in content:gmatch("rule%s*%(%s*\"(.-)\"%s*%)") do + rulefiles[rulename] = filepath + end + end + end + end + rule._RULEFILES = rulefiles + end + return rulefiles[name] +end + +-- load the rules which may provide the given rule name +-- +-- there are hundreds of builtin rules, but a project only uses a few of them, +-- so we do not load all of them, we only load the group which may provide it, +-- e.g. mode.debug -> <rulesdir>/mode/**/xmake.lua +-- +function rule._load_ondemand(name) + + -- it has been loaded with another group? e.g. c.build.pcheader comes with the c++ group + local loaded = rule._LOADED + if loaded == nil then + loaded = {} + rule._LOADED = loaded + end + local instance = loaded[name] + if instance then + return instance + end + + local groups = rule._GROUPS + if groups == nil then + groups = {} + rule._GROUPS = groups + end + + -- the rules of an addon are always referenced with its name, + -- e.g. add_rules("@addon/esp32/flash"), so we only load this addon + local maxrecursion = 4 + local groupkey, files, opt + if name:startswith("@addon/") then + local referenceinfo = addon.resolve_reference(name, "/", "rules") + if not referenceinfo then + return + end + groupkey = "@addon/" .. referenceinfo.addon + files = os.files(path.join(referenceinfo.dir, "**/xmake.lua"), {recursion = maxrecursion}) + opt = {prefix = groupkey .. "/"} + else + -- the group is the first part of the rule name, and it's usually the directory + -- name of its rules, e.g. mode.debug -> <rulesdir>/mode + groupkey = name:split(".", {plain = true})[1] + files = {} + for _, dir in ipairs(rule._directories()) do + local groupdir = path.join(dir, groupkey) + table.join2(files, os.files(path.join(groupdir, "xmake.lua"))) + table.join2(files, os.files(path.join(groupdir, "**/xmake.lua"), {recursion = maxrecursion})) + end + + -- the rule name does not match its directory name? we can only get its file + -- from the rule declarations, e.g. c.build -> <rulesdir>/c++/xmake.lua + if #files == 0 then + local rulefile = rule._rulefile(name) + if not rulefile then + return + end + groupkey = rulefile + files = {rulefile} + end + end + + if not groups[groupkey] then + local ruleinfos = {} + rule._load_rulefiles(ruleinfos, files, opt) + for rulename, ruleinfo in pairs(ruleinfos) do + loaded[rulename] = rule.new(rulename, ruleinfo) + end + groups[groupkey] = true + end + return loaded[name] +end + +-- report the missing addon of the given rule reference, e.g. add_rules("@addon/esp32/flash") +-- +-- it's either not installed at all, or it's installed but does not provide this rule +-- +function rule._raise_addon_notfound(name) + local referenceinfo, errors = addon.resolve_reference(name, "/", "rules") + if errors then + os.raise(errors) + end + os.raise("rule(%s) not found!\nplease install the addon which provides it first: xmake addon --install %s", + name, referenceinfo and referenceinfo.addon or "<addon>") +end + +-- clear the loaded rules, e.g. some addons may be installed just now +function rule.clear() + rule._RULES = nil + rule._GROUPS = nil + rule._LOADED = nil + rule._RULEFILES = nil +end + -- get the given global rule +-- +-- @param name the rule name, the rules of the installed addons need the +-- `@addon/<addon>/` prefix, e.g. "@addon/esp32/flash" +-- function rule.rule(name) - return rule.rules()[name] + local instance + if rule._RULES then + -- all the rules have been loaded, e.g. rule.rules() + instance = rule._RULES[name] + else + -- we only load the rules which may provide it + instance = rule._load_ondemand(name) + if instance == nil then + -- @note the rule name may not match its directory name, so we need + -- to load all the rules to be sure that it does not exist + instance = rule.rules()[name] + end + end + if instance == nil and name:startswith("@addon/") then + rule._raise_addon_notfound(name) + end + return instance +end + +-- load the rules from the given directory +function rule._load_rules(ruleinfos, dir, opt) + -- @note we may load a group directory directly, e.g. <rulesdir>/mode/xmake.lua + rule._load_rulefiles(ruleinfos, table.join(os.files(path.join(dir, "xmake.lua")), + os.files(path.join(dir, "**/xmake.lua"))), opt) +end + +-- load the rules from the given files +function rule._load_rulefiles(ruleinfos, files, opt) + opt = opt or {} + if files then + for _, filepath in ipairs(files) do + local results, errors = rule._load(filepath) + if results then + for rulename, ruleinfo in pairs(results) do + -- the addon rules are always referenced with the addon name, + -- e.g. add_rules("@addon/esp32/flash") + local fullname = (opt.prefix or "") .. rulename + if opt.prefix and ruleinfos[fullname] == nil then + -- the addon rules can depend on the other rules of the same addon, + -- e.g. add_deps("@self/base") -> add_deps("@addon/<addon>/base") + rule._replace_selfdeps(ruleinfo, opt.prefix) + end + ruleinfos[fullname] = ruleinfo + end + else + os.raise(errors) + end + end + end +end + +-- replace the `@self/` dependencies of the addon rules with the full names +function rule._replace_selfdeps(ruleinfo, prefix) + local deps = {} + local replace = function (depname) + if depname:startswith("@self/") then + return prefix .. depname:sub(#"@self/" + 1) + end + return depname + end + for _, depname in ipairs(table.wrap(ruleinfo:get("deps"))) do + table.insert(deps, replace(depname)) + end + if #deps > 0 then + ruleinfo:set("deps", table.unwrap(deps)) + end + for depname, extraconf in pairs(table.wrap(ruleinfo:extraconf("deps"))) do + local newname = replace(depname) + if newname ~= depname then + ruleinfo:extraconf_set("deps", newname, extraconf) + end + end end -- get global rules @@ -463,26 +665,21 @@ function rule.rules() local rules = rule._RULES if rules == nil then local ruleinfos = {} - local dirs = rule._directories() - for _, dir in ipairs(dirs) do - local files = os.files(path.join(dir, "**/xmake.lua")) - if files then - for _, filepath in ipairs(files) do - local results, errors = rule._load(filepath) - if results then - table.join2(ruleinfos, results) - else - os.raise(errors) - end - end - end + for _, dir in ipairs(rule._directories()) do + rule._load_rules(ruleinfos, dir) + end + for _, addoninfo in ipairs(rule._addon_directories()) do + rule._load_rules(ruleinfos, addoninfo.dir, {prefix = "@addon/" .. addoninfo.name .. "/"}) end -- make rule instances + -- + -- @note we reuse the rules which have been loaded on demand, + -- otherwise we would have two instances of the same rule + local loaded = rule._LOADED or {} rules = {} for rulename, ruleinfo in pairs(ruleinfos) do - local instance = rule.new(rulename, ruleinfo) - rules[rulename] = instance + rules[rulename] = loaded[rulename] or rule.new(rulename, ruleinfo) end rule._RULES = rules end diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua index cc5df14d4..e51ffeb8b 100644 --- a/xmake/core/project/target.lua +++ b/xmake/core/project/target.lua @@ -84,7 +84,7 @@ function _instance:_load_rule(ruleinst, suffix) if cache[key] == nil then local on_load = ruleinst:script("load" .. (suffix and ("_" .. suffix) or "")) if on_load then - local ok, errors = sandbox.load(on_load, self) + local ok, errors = sandbox.call(on_load, self) cache[key] = {ok, errors} else cache[key] = {true} @@ -129,7 +129,7 @@ function _instance:_load() -- do load for target local on_load = self:script("load") if on_load then - ok, errors = sandbox.load(on_load, self) + ok, errors = sandbox.call(on_load, self) if not ok then return false, errors end @@ -159,7 +159,7 @@ function _instance:_load_after() -- do load for target local after_load = self:script("load_after") if after_load then - local ok, errors = sandbox.load(after_load, self) + local ok, errors = sandbox.call(after_load, self) if not ok then return false, errors end @@ -3296,6 +3296,14 @@ function target.linkname(filename, opt) linkname, count = filename:gsub(target.filename("__pattern__", "static", {plat = "windows"}):gsub("%.", "%%."):gsub("__pattern__", "(.+)") .. "$", "%1") end if count > 0 and linkname then + -- the library name itself may end with `.lib`, e.g. vcpkg installs `Luau.CLI.lib.lib`, + -- we cannot strip it, nf_link() passes the names ending with `.lib` to the linker + -- as-is, and it would look for `Luau.CLI.lib` + -- + -- @see https://github.com/xmake-io/xmake/issues/7708 + if opt.plat == "windows" and linkname:endswith(".lib") then + return filename + end return linkname end -- fallback to the generic unix library name, libxxx.a, libxxx.so, .. diff --git a/xmake/core/sandbox/modules/import/core/base/scheduler.lua b/xmake/core/sandbox/modules/import/core/base/scheduler.lua index 222bee391..a3f9741c3 100644 --- a/xmake/core/sandbox/modules/import/core/base/scheduler.lua +++ b/xmake/core/sandbox/modules/import/core/base/scheduler.lua @@ -96,7 +96,11 @@ end -- resume the given coroutine function sandbox_core_base_scheduler.co_resume(co, ...) - return scheduler:resume(co:thread(), ...) + local ok, errors = scheduler:co_resume(co, ...) + if not ok then + raise(errors) + end + return ok, errors end -- suspend the current coroutine diff --git a/xmake/core/sandbox/modules/import/core/base/semver.lua b/xmake/core/sandbox/modules/import/core/base/semver.lua index 45ba8b74f..04df315eb 100644 --- a/xmake/core/sandbox/modules/import/core/base/semver.lua +++ b/xmake/core/sandbox/modules/import/core/base/semver.lua @@ -50,15 +50,10 @@ function sandbox_core_base_semver.match(str, pos, pattern) end -- is valid version? -function sandbox_core_base_semver.is_valid(version) - return semver.parse(version) ~= nil -end +sandbox_core_base_semver.is_valid = semver.is_valid -- is valid version range? -function sandbox_core_base_semver.is_valid_range(range) - local ok = semver.satisfies("1.0", range) - return ok ~= nil -end +sandbox_core_base_semver.is_valid_range = semver.is_valid_range -- compare two version strings -- diff --git a/xmake/core/sandbox/modules/import/core/package/addon.lua b/xmake/core/sandbox/modules/import/core/package/addon.lua new file mode 100644 index 000000000..9f080cc93 --- /dev/null +++ b/xmake/core/sandbox/modules/import/core/package/addon.lua @@ -0,0 +1,96 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file addon.lua +-- + +-- define module +local sandbox_core_package_addon = sandbox_core_package_addon or {} + +-- load modules +local addon = require("package/addon") +local raise = require("sandbox/modules/raise") + +-- inherit some builtin interfaces +sandbox_core_package_addon.installdir = addon.installdir +sandbox_core_package_addon.workdir = addon.workdir +sandbox_core_package_addon.dirname = addon.dirname +sandbox_core_package_addon.owner = addon.owner +sandbox_core_package_addon.payloadinfos = addon.payloadinfos +sandbox_core_package_addon.payloads_of = addon.payloads_of +sandbox_core_package_addon.payloadroot = addon.payloadroot +sandbox_core_package_addon.addons = addon.addons +sandbox_core_package_addon.versions = addon.versions +sandbox_core_package_addon.unregister = addon.unregister + +-- get the manifest of the given addon directory, e.g. <sourcedir>/addon.lua +-- +-- @param sourcedir the addon source or install directory +-- @return the manifest, it will be nil if this addon does not describe itself +-- +function sandbox_core_package_addon.manifest(sourcedir) + local manifest, errors = addon.manifest(sourcedir) + if errors then + raise(errors) + end + return manifest +end + +-- resolve the given addon reference, e.g. `@addon/<addon>/<name>`, `@self/<name>` +-- +-- @param reference the addon reference +-- @param sep the separator, e.g. "/", "." +-- @param kind the payload kind, e.g. "rules", "modules" +-- @param opt the options, e.g. {scriptdir = "..."} +-- +-- @return the reference information, e.g. {dir = "...", name = "flash", addon = "esp32"} +-- +function sandbox_core_package_addon.resolve_reference(reference, sep, kind, opt) + local referenceinfo, errors = addon.resolve_reference(reference, sep, kind, opt) + if errors then + raise(errors) + end + return referenceinfo +end + +-- register the given installed addon +-- +-- @param name the addon name +-- @param version the addon version, e.g. "1.0.1", "latest" +-- @param opt the options, e.g. {description = "...", deps = {"foo"}} +-- +function sandbox_core_package_addon.register(name, version, opt) + local ok, errors = addon.register(name, version, opt) + if not ok then + raise(errors) + end +end + +-- remove the given installed addon +-- +-- @param name the addon name +-- @param opt the options, e.g. {force = true} +-- +function sandbox_core_package_addon.remove(name, opt) + local ok, errors = addon.remove(name, opt) + if not ok then + raise(errors) + end +end + +-- return module +return sandbox_core_package_addon diff --git a/xmake/core/sandbox/modules/import/core/project/addons.lua b/xmake/core/sandbox/modules/import/core/project/addons.lua new file mode 100644 index 000000000..ff2fe14c0 --- /dev/null +++ b/xmake/core/sandbox/modules/import/core/project/addons.lua @@ -0,0 +1,35 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file addons.lua +-- + +-- define module +local sandbox_core_project_addons = sandbox_core_project_addons or {} + +-- load modules +local addons = require("project/addons") + +-- inherit some builtin interfaces +sandbox_core_project_addons.lockfile = addons.lockfile +sandbox_core_project_addons.lockfile_version = addons.lockfile_version +sandbox_core_project_addons.locked = addons.locked +sandbox_core_project_addons.locked_valid = addons.locked_valid +sandbox_core_project_addons.requirename = addons.requirename + +-- return module +return sandbox_core_project_addons diff --git a/xmake/core/sandbox/modules/import/core/project/project.lua b/xmake/core/sandbox/modules/import/core/project/project.lua index 9b69349d0..4964d988c 100644 --- a/xmake/core/sandbox/modules/import/core/project/project.lua +++ b/xmake/core/sandbox/modules/import/core/project/project.lua @@ -161,6 +161,10 @@ end]] function sandbox_core_project._load_package_rules_for_target(target) for _, rulename in ipairs(table.wrap(target:get("rules"))) do local packagename = rulename:match("@(.-)/") + -- @note we need to ignore the addon rules, e.g. add_rules("@addon/foo") + if packagename == "addon" then + packagename = nil + end if packagename then local ruleinst local pkginfo = project.required_package(packagename) diff --git a/xmake/core/sandbox/modules/import/core/sandbox/module.lua b/xmake/core/sandbox/modules/import/core/sandbox/module.lua index 2090c1f52..294cf7556 100644 --- a/xmake/core/sandbox/modules/import/core/sandbox/module.lua +++ b/xmake/core/sandbox/modules/import/core/sandbox/module.lua @@ -30,6 +30,7 @@ local table = require("base/table") local string = require("base/string") local option = require("base/option") local global = require("base/global") +local addon = require("package/addon") local config = require("project/config") local memcache = require("cache/memcache") local sandbox = require("sandbox/sandbox") @@ -386,7 +387,7 @@ function core_sandbox_module._find_and_load(name, opt) errors = moduleinfo[2] else module, errors = core_sandbox_module._load(moduledir, name, { - instance = idx < #modules_directories and opt.instance or nil, -- last modules need not fork sandbox + instance = moduledir ~= core_sandbox_module.coredir() and opt.instance or nil, -- the core modules need not fork sandbox module = module, always_build = always_build, modulekind = modulekind}) @@ -419,9 +420,10 @@ end function core_sandbox_module.directories() local moduledirs = memcache.get("core_sandbox_module", "moduledirs") if not moduledirs then + -- @note the core modules directory must be the last one, @see core_sandbox_module._find_and_load moduledirs = { path.join(global.directory(), "modules"), path.join(os.programdir(), "modules"), - path.join(os.programdir(), "core/sandbox/modules/import")} + core_sandbox_module.coredir()} local modulesdir = os.getenv("XMAKE_MODULES_DIR") if modulesdir and os.isdir(modulesdir) then table.insert(moduledirs, 1, modulesdir) @@ -431,6 +433,14 @@ function core_sandbox_module.directories() return moduledirs end +-- get the core modules directory +-- +-- @note the modules in this directory are loaded without sandbox, because they need `require` +-- +function core_sandbox_module.coredir() + return path.join(os.programdir(), "core/sandbox/modules/import") +end + -- add module directories function core_sandbox_module.add_directories(...) local moduledirs = core_sandbox_module.directories() @@ -442,6 +452,14 @@ end -- find module function core_sandbox_module.find(name) + + -- an addon can export some modules as the global modules, they are also visible here, + -- e.g. find_toolname() looks for `detect.tools.find_xxx` with it, @see addon.globalmodules() + local globalmodulesdir = addon.globalmodules()[name] + if globalmodulesdir and core_sandbox_module._find(globalmodulesdir, name) then + return true + end + for _, moduledir in ipairs(core_sandbox_module.directories()) do if (core_sandbox_module._find(moduledir, name)) then return true @@ -498,6 +516,24 @@ function core_sandbox_module.import(name, opt) local scope_parent = getfenv(2) assert(scope_parent) + -- import the modules of the installed addons? e.g. import("@addon.foo") + -- + -- @note we need the `@addon.` prefix to distinguish them from the builtin modules + -- + -- import the modules of an addon? + -- e.g. import("@addon.esp32.sdkconfig"), import("@self.sdkconfig") + local addon_modulesdir + local addon_reference = name + if addon.is_reference(name, ".") then + local referenceinfo, errors = addon.resolve_reference(name, ".", "modules", + {scriptdir = opt.scriptdir or sandbox.instance() and sandbox.instance():rootdir()}) + if not referenceinfo then + raise(errors) + end + addon_modulesdir = referenceinfo.dir + name = referenceinfo.name + end + -- get module name local modulename = core_sandbox_module.name(name) if not modulename then @@ -515,7 +551,25 @@ function core_sandbox_module.import(name, opt) local rootdir = opt.rootdir or instance:rootdir() -- init module directories (disable local packages?) - local modules_directories = (opt.nolocal or not rootdir) and core_sandbox_module.directories() or table.join(rootdir, core_sandbox_module.directories()) + local modules_directories + if addon_modulesdir then + -- the addon modules are always resolved from the addon `modules` directory only, + -- e.g. import("@addon.esp32.sdkconfig"), import("@self.sdkconfig") + modules_directories = {addon_modulesdir} + else + modules_directories = (opt.nolocal or not rootdir) and core_sandbox_module.directories() or table.join(rootdir, core_sandbox_module.directories()) + + -- an addon can export some modules as the global modules, e.g. add_globalmodules("core.tools.esptool"), + -- so that the internal calls can import them with their plain names, e.g. import("core.tools.esptool") + -- + -- @note we only accept the declared names, the other modules of this addon are + -- still private and can only be imported with `@addon.`/`@self.` + -- + local globalmodulesdir = addon.globalmodules()[name] + if globalmodulesdir then + table.insert(modules_directories, rootdir and 2 or 1, globalmodulesdir) + end + end -- load module local loadopt = table.clone(opt) or {} @@ -554,6 +608,8 @@ function core_sandbox_module.import(name, opt) if not found then if opt.try then return nil + elseif addon_modulesdir then + raise("cannot import module: %s, not found!", addon_reference) else raise("cannot import module: %s, not found!", name) end diff --git a/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua b/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua index 0a9cae170..7303e901e 100644 --- a/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua +++ b/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua @@ -134,6 +134,19 @@ function sandbox_core_sandbox.filter(script) return instance:filter() end +-- fork a new sandbox and bind a raw script +function sandbox_core_sandbox.fork(script) + local instance = sandbox.instance() + if not instance then + raise("cannot get sandbox instance!") + end + local newinst, errors = instance:fork(script) + if not newinst then + raise(errors) + end + return newinst +end + -- get all builtin modules function sandbox_core_sandbox.builtin_modules() return sandbox.builtin_modules() diff --git a/xmake/core/sandbox/modules/import/core/tool/compiler.lua b/xmake/core/sandbox/modules/import/core/tool/compiler.lua index 71de70d2a..28a3d4d92 100644 --- a/xmake/core/sandbox/modules/import/core/tool/compiler.lua +++ b/xmake/core/sandbox/modules/import/core/tool/compiler.lua @@ -207,7 +207,7 @@ function sandbox_core_tool_compiler.features(langkind, opt) local flags = instance:compflags(opt) -- get features - local ok, results_or_errors = sandbox.load(sandbox_core_tool_compiler._features, instance:name(), {flags = flags, program = instance:program(), envs = instance:runenvs()}) + local ok, results_or_errors = sandbox.call(sandbox_core_tool_compiler._features, instance:name(), {flags = flags, program = instance:program(), envs = instance:runenvs()}) if not ok then raise(results_or_errors) end @@ -259,7 +259,7 @@ function sandbox_core_tool_compiler.has_features(features, opt) for sourcekind, features in pairs(features_by_kind) do local instance = sandbox_core_tool_compiler.load(sourcekind, opt) local flags = instance:compflags(opt) - local ok, results_or_errors = sandbox.load(sandbox_core_tool_compiler._has_features, instance:name(), features, {flags = flags, program = instance:program(), envs = instance:runenvs()}) + local ok, results_or_errors = sandbox.call(sandbox_core_tool_compiler._has_features, instance:name(), features, {flags = flags, program = instance:program(), envs = instance:runenvs()}) if not ok then raise(results_or_errors) end diff --git a/xmake/core/sandbox/modules/import/lib/detect/find_directory.lua b/xmake/core/sandbox/modules/import/lib/detect/find_directory.lua index 63392a751..ad48cff73 100644 --- a/xmake/core/sandbox/modules/import/lib/detect/find_directory.lua +++ b/xmake/core/sandbox/modules/import/lib/detect/find_directory.lua @@ -36,7 +36,7 @@ function sandbox_lib_detect_find_directory._expand_paths(paths) for _, _path in ipairs(table.wrap(paths)) do local _path = _path if type(_path) == "function" then - local ok, result_or_errors = sandbox.load(_path) + local ok, result_or_errors = sandbox.call(_path) if ok then _path = result_or_errors or "" else diff --git a/xmake/core/sandbox/modules/import/lib/detect/find_file.lua b/xmake/core/sandbox/modules/import/lib/detect/find_file.lua index e642f45b7..67db6c443 100644 --- a/xmake/core/sandbox/modules/import/lib/detect/find_file.lua +++ b/xmake/core/sandbox/modules/import/lib/detect/find_file.lua @@ -37,7 +37,7 @@ function sandbox_lib_detect_find_file._expand_paths(paths) for _, _path in ipairs(table.wrap(paths)) do local _path = _path if type(_path) == "function" then - local ok, result_or_errors = sandbox.load(_path) + local ok, result_or_errors = sandbox.call(_path) if ok then _path = result_or_errors or "" else diff --git a/xmake/core/sandbox/modules/import/lib/detect/find_path.lua b/xmake/core/sandbox/modules/import/lib/detect/find_path.lua index 159d7dbdc..6dd775752 100644 --- a/xmake/core/sandbox/modules/import/lib/detect/find_path.lua +++ b/xmake/core/sandbox/modules/import/lib/detect/find_path.lua @@ -36,7 +36,7 @@ function sandbox_lib_detect_find_path._expand_paths(paths) for _, _path in ipairs(table.wrap(paths)) do local _path = _path if type(_path) == "function" then - local ok, result_or_errors = sandbox.load(_path) + local ok, result_or_errors = sandbox.call(_path) if ok then _path = result_or_errors or "" else diff --git a/xmake/core/sandbox/modules/import/lib/detect/find_program.lua b/xmake/core/sandbox/modules/import/lib/detect/find_program.lua index 0ca3f8d19..eee1d13b6 100644 --- a/xmake/core/sandbox/modules/import/lib/detect/find_program.lua +++ b/xmake/core/sandbox/modules/import/lib/detect/find_program.lua @@ -64,7 +64,7 @@ function sandbox_lib_detect_find_program._do_check(program, opt) elseif type(opt.check) == "table" then ok, errors = os.runv(program, opt.check, {envs = opt.envs, shell = opt.shell}) else - ok, errors = sandbox.load(opt.check, program) + ok, errors = sandbox.call(opt.check, program) end -- check failed? print verbose error info @@ -112,7 +112,7 @@ function sandbox_lib_detect_find_program._find_from_paths(name, paths, opt) -- format path for builtin variables if type(_path) == "function" then - local ok, results = sandbox.load(_path) + local ok, results = sandbox.call(_path) if ok then _path = results or "" else diff --git a/xmake/core/sandbox/modules/import/lib/detect/find_programver.lua b/xmake/core/sandbox/modules/import/lib/detect/find_programver.lua index 0d76526e5..2a8629855 100644 --- a/xmake/core/sandbox/modules/import/lib/detect/find_programver.lua +++ b/xmake/core/sandbox/modules/import/lib/detect/find_programver.lua @@ -79,7 +79,7 @@ function sandbox_lib_detect_find_programver.main(program, opt) local outdata = nil local command = opt.command if type(command) == "function" then - ok, outdata = sandbox.load(command) + ok, outdata = sandbox.call(command) if not ok and outdata and option.get("diagnosis") then utils.cprint("${color.warning}checkinfo: ${clear dim}" .. outdata) end @@ -94,7 +94,7 @@ function sandbox_lib_detect_find_programver.main(program, opt) if ok and outdata and #outdata > 0 then local parse = opt.parse if type(parse) == "function" then - ok, result = sandbox.load(parse, outdata) + ok, result = sandbox.call(parse, outdata) if not ok and result and option.get("diagnosis") then utils.cprint("${color.warning}checkinfo: ${clear dim}" .. result) result = nil diff --git a/xmake/core/sandbox/modules/import/lib/lua/error.lua b/xmake/core/sandbox/modules/import/lib/lua/error.lua new file mode 100644 index 000000000..4f38f1647 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/error.lua @@ -0,0 +1,36 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file error.lua +-- + +-- the native lua `error` +-- +-- it is not in the sandbox by default, `raise` is the one to use: it formats the +-- message and it is what `try`/`catch` understands. `error` is the plain one, for the +-- code which wants to throw a value rather than a message +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.error") +-- +-- error("something went wrong") +-- error({code = 1}) -- a value, not a message +-- +return error diff --git a/xmake/core/sandbox/modules/import/lib/lua/getmetatable.lua b/xmake/core/sandbox/modules/import/lib/lua/getmetatable.lua new file mode 100644 index 000000000..fcef76eb3 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/getmetatable.lua @@ -0,0 +1,32 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file getmetatable.lua +-- + +-- the native lua `getmetatable` +-- +-- @note the same in lua 5.1 and 5.4, it returns the `__metatable` field when the +-- metatable is protected +-- +-- e.g. +-- +-- import("lib.lua.getmetatable") +-- +-- local mt = getmetatable(obj) +-- +return getmetatable diff --git a/xmake/core/sandbox/modules/import/lib/lua/next.lua b/xmake/core/sandbox/modules/import/lib/lua/next.lua new file mode 100644 index 000000000..65313dd1a --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/next.lua @@ -0,0 +1,36 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file next.lua +-- + +-- the native lua `next` +-- +-- it is not in the sandbox by default, `pairs` covers the iteration of a table. `next` +-- is what is left for the two things `pairs` cannot say: whether a table is empty, and +-- stepping a traversal by hand +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.next") +-- +-- if next(tbl) == nil then ... end -- the table is empty +-- local key, value = next(tbl) -- the first entry, in no particular order +-- +return next diff --git a/xmake/core/sandbox/modules/import/lib/lua/pcall.lua b/xmake/core/sandbox/modules/import/lib/lua/pcall.lua new file mode 100644 index 000000000..1ad150943 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/pcall.lua @@ -0,0 +1,36 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file pcall.lua +-- + +-- the native lua `pcall` +-- +-- it is not in the sandbox by default, `try`/`catch` is the idiomatic way to handle the +-- errors of a script, and it keeps the traceback and the error message which xmake +-- builds. `pcall` is the plain one, for the code which only needs a boolean +-- +-- @note the same in lua 5.1 and 5.4. `xpcall` is not exported, its message handler +-- takes the extra arguments only since 5.2 +-- +-- e.g. +-- +-- import("lib.lua.pcall") +-- +-- local ok, result = pcall(function () return 1 end) +-- +return pcall diff --git a/xmake/core/sandbox/modules/import/lib/lua/rawequal.lua b/xmake/core/sandbox/modules/import/lib/lua/rawequal.lua new file mode 100644 index 000000000..b9f9ea683 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/rawequal.lua @@ -0,0 +1,33 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file rawequal.lua +-- + +-- the native lua `rawequal` +-- +-- it compares two values without going through the `__eq` metamethod +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.rawequal") +-- +-- if rawequal(a, b) then ... end +-- +return rawequal diff --git a/xmake/core/sandbox/modules/import/lib/lua/rawget.lua b/xmake/core/sandbox/modules/import/lib/lua/rawget.lua new file mode 100644 index 000000000..fe5115001 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/rawget.lua @@ -0,0 +1,34 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file rawget.lua +-- + +-- the native lua `rawget` +-- +-- it reads a field of a table without going through its `__index` metamethod, so it +-- sees what the table itself holds and not what its metatable would answer +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.rawget") +-- +-- local value = rawget(tbl, "key") +-- +return rawget diff --git a/xmake/core/sandbox/modules/import/lib/lua/rawset.lua b/xmake/core/sandbox/modules/import/lib/lua/rawset.lua new file mode 100644 index 000000000..917bc3d86 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/rawset.lua @@ -0,0 +1,33 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file rawset.lua +-- + +-- the native lua `rawset` +-- +-- it writes a field of a table without going through its `__newindex` metamethod +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.rawset") +-- +-- rawset(tbl, "key", value) +-- +return rawset diff --git a/xmake/core/sandbox/modules/import/lib/lua/select.lua b/xmake/core/sandbox/modules/import/lib/lua/select.lua new file mode 100644 index 000000000..45fb1bbc9 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/select.lua @@ -0,0 +1,36 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file select.lua +-- + +-- the native lua `select` +-- +-- it is not in the sandbox by default, the scripts of a project rarely need to look at +-- a raw argument list, but it is the only way to count the arguments of a vararg +-- function without losing the nils in it +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.select") +-- +-- local count = select("#", ...) -- how many arguments, nils included +-- local second = select(2, ...) -- everything from the second one on +-- +return select diff --git a/xmake/core/sandbox/modules/import/lib/lua/setmetatable.lua b/xmake/core/sandbox/modules/import/lib/lua/setmetatable.lua new file mode 100644 index 000000000..6f1d4c330 --- /dev/null +++ b/xmake/core/sandbox/modules/import/lib/lua/setmetatable.lua @@ -0,0 +1,36 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file setmetatable.lua +-- + +-- the native lua `setmetatable` +-- +-- it is not in the sandbox by default: a module which builds objects with metatables is +-- a module which is hard to serialize and to cache, and xmake passes plain tables +-- around on purpose. it is here for the code which really wants operator overloading or +-- an `__index` fallback +-- +-- @note the same in lua 5.1 and 5.4 +-- +-- e.g. +-- +-- import("lib.lua.setmetatable") +-- +-- local obj = setmetatable({}, {__index = function (tbl, key) return "?" end}) +-- +return setmetatable diff --git a/xmake/core/sandbox/sandbox.lua b/xmake/core/sandbox/sandbox.lua index 758a48030..13e598b73 100644 --- a/xmake/core/sandbox/sandbox.lua +++ b/xmake/core/sandbox/sandbox.lua @@ -105,43 +105,13 @@ function sandbox._new() instance:_api_register_builtin(module_name, module) end - -- bind instance to the public script envirnoment - instance:bind(instance._PUBLIC) + -- bind the public script envirnoment + instance:_bindenv(instance._PUBLIC) return instance end --- new a sandbox instance with the given script -function sandbox.new(script, opt) - opt = opt or {} - - -- new instance - local self = sandbox._new() - assert(self and self._PUBLIC and self._PRIVATE) - - self._PRIVATE._FILTER = opt.filter - self._PRIVATE._ROOTDIR = opt.rootdir - self._PRIVATE._NAMESPACE = opt.namespace - - -- invalid script? - if type(script) ~= "function" then - return nil, "invalid script!" - end - - -- bind public scope - setfenv(script, self._PUBLIC) - - -- save script - self._PRIVATE._SCRIPT = script - return self -end - --- load script in the sandbox -function sandbox.load(script, ...) - return utils.trycall(script, sandbox._traceback, ...) -end - --- bind self instance to the given script or envirnoment -function sandbox:bind(script_or_env) +-- bind the given script or envirnoment and the self instance +function sandbox:_bindenv(script_or_env) -- get envirnoment local env = script_or_env @@ -150,20 +120,18 @@ function sandbox:bind(script_or_env) end -- bind instance to the script envirnoment - setmetatable(env, { __index = function (tbl, key) - if type(key) == "string" and key == "_SANDBOX" and rawget(tbl, "_SANDBOX_READABLE") then - return self - end - return rawget(tbl, key) + setmetatable(env, { __index = function (tbl, key) + if type(key) == "string" and key == "_SANDBOX" and rawget(tbl, "_SANDBOX_READABLE") then + return self end - , __newindex = function (tbl, key, val) - if type(key) == "string" and (key == "_SANDBOX" or key == "_SANDBOX_READABLE") then - return - end - rawset(tbl, key, val) - end}) - - -- ok + return rawget(tbl, key) + end, + __newindex = function (tbl, key, val) + if type(key) == "string" and (key == "_SANDBOX" or key == "_SANDBOX_READABLE") then + return + end + rawset(tbl, key, val) + end}) return script_or_env end @@ -205,7 +173,7 @@ function sandbox:module() table.copy2(scope_backup, scope_public) -- load module with sandbox - local ok, errors = sandbox.load(self:script()) + local ok, errors = sandbox.call(self:script()) if not ok then return nil, errors end @@ -250,6 +218,36 @@ function sandbox:api_register_builtin(name, func) sandbox._api_register_builtin(self, name, func) end +-- new a sandbox instance with the given script +function sandbox.new(script, opt) + opt = opt or {} + + -- new instance + local self = sandbox._new() + assert(self and self._PUBLIC and self._PRIVATE) + + self._PRIVATE._FILTER = opt.filter + self._PRIVATE._ROOTDIR = opt.rootdir + self._PRIVATE._NAMESPACE = opt.namespace + + -- invalid script? + if type(script) ~= "function" then + return nil, "invalid script!" + end + + -- bind public scope + setfenv(script, self._PUBLIC) + + -- save script + self._PRIVATE._SCRIPT = script + return self +end + +-- call script in the sandbox +function sandbox.call(script, ...) + return utils.trycall(script, sandbox._traceback, ...) +end + -- get current instance in the sandbox modules function sandbox.instance(script) @@ -331,6 +329,5 @@ function sandbox.builtin_modules() return builtin_modules end - -- return module return sandbox diff --git a/xmake/core/tool/compiler.lua b/xmake/core/tool/compiler.lua index e00505a4f..44349de5f 100644 --- a/xmake/core/tool/compiler.lua +++ b/xmake/core/tool/compiler.lua @@ -238,7 +238,7 @@ function compiler:build(sourcefiles, targetfile, opt) if not targetkind and opt.target and opt.target.targetkind then targetkind = opt.target:kind() end - return sandbox.load(self:_tool().build, self:_tool(), sourcefiles, targetkind or "binary", targetfile, flags, opt) + return sandbox.call(self:_tool().build, self:_tool(), sourcefiles, targetkind or "binary", targetfile, flags, opt) end -- get the build arguments list (compile and link) @@ -297,7 +297,7 @@ function compiler:compile(sourcefiles, objectfile, opt) opt = table.copy(opt) opt.target = self:target() profiler:enter(self:name(), "compile", sourcefiles) - local ok, errors = sandbox.load(self:_tool().compile, self:_tool(), sourcefiles, objectfile, opt.dependinfo, compflags, opt) + local ok, errors = sandbox.call(self:_tool().compile, self:_tool(), sourcefiles, objectfile, opt.dependinfo, compflags, opt) profiler:leave(self:name(), "compile", sourcefiles) return ok, errors end diff --git a/xmake/core/tool/linker.lua b/xmake/core/tool/linker.lua index 9cdff8840..7eaecc666 100644 --- a/xmake/core/tool/linker.lua +++ b/xmake/core/tool/linker.lua @@ -242,7 +242,7 @@ function linker:link(objectfiles, targetfile, opt) opt = opt or {} local linkflags = opt.linkflags or self:linkflags(opt) profiler:enter(self:name(), "link", targetfile) - local ok, errors = sandbox.load(self:_tool().link, self:_tool(), + local ok, errors = sandbox.call(self:_tool().link, self:_tool(), table.wrap(objectfiles), self:_targetkind(), targetfile, linkflags, table.join(opt, {target = self:target()})) profiler:leave(self:name(), "link", targetfile) diff --git a/xmake/core/tool/tool.lua b/xmake/core/tool/tool.lua index c54e24c93..9d0dfa0d6 100644 --- a/xmake/core/tool/tool.lua +++ b/xmake/core/tool/tool.lua @@ -62,7 +62,7 @@ function _instance.new(kind, name, program, plat, arch, toolchain_inst) -- init instance if instance.init then - local ok, errors = sandbox.load(instance.init, instance) + local ok, errors = sandbox.call(instance.init, instance) if not ok then return nil, errors end @@ -176,7 +176,7 @@ end function _instance:_load_once() if not self._LOADED then if self.load then - local ok, errors = sandbox.load(self.load, self) + local ok, errors = sandbox.call(self.load, self) if not ok then return false, errors end @@ -274,7 +274,7 @@ function tool.load(kind, opt) tool._find_toolname = tool._find_toolname or import("lib.detect.find_toolname") -- get the tool name from the program - local ok, name_or_errors = sandbox.load(tool._find_toolname, toolname or program, {program = program}) + local ok, name_or_errors = sandbox.call(tool._find_toolname, toolname or program, {program = program}) if not ok then return nil, name_or_errors end diff --git a/xmake/core/tool/toolchain.lua b/xmake/core/tool/toolchain.lua index 3bca7e37a..7b841a018 100644 --- a/xmake/core/tool/toolchain.lua +++ b/xmake/core/tool/toolchain.lua @@ -33,6 +33,7 @@ local hashset = require("base/hashset") local scopeinfo = require("base/scopeinfo") local interpreter = require("base/interpreter") local is_cross = require("base/private/is_cross") +local addon = require("package/addon") local config = require("project/config") local memcache = require("cache/memcache") local localcache = require("cache/localcache") @@ -356,7 +357,7 @@ function _instance:check() if checked == nil then local on_check = self:_on_check() if on_check then - local ok, results_or_errors = sandbox.load(on_check, self) + local ok, results_or_errors = sandbox.call(on_check, self) if ok then checked = results_or_errors else @@ -449,7 +450,7 @@ function _instance:_load() local on_load = self:_on_load() if on_load then info:set("__loading", true) - local ok, errors = sandbox.load(on_load, self) + local ok, errors = sandbox.call(on_load, self) info:set("__loading", false) if not ok then os.raise(errors) @@ -670,6 +671,28 @@ end -- e.g. "mingw[clang]@llvm-mingw", "msvc[vs=2025,..]" -- function toolchain.parsename(name) + + -- the toolchain of an addon? + -- e.g. set_toolchains("@addon/esp32/xtensa"), set_toolchains("@addon/esp32/clang@llvm"), set_toolchains("@self/xtensa") + -- + -- @note we need to parse it first, because `@` is also used for the toolchain packages, e.g. "@zig" + -- + -- @note we only strip the `@addon/<addon>/` prefix here, the rest is parsed as usual, + -- so the addon toolchains can also be bound to packages, e.g. "@addon/esp32/clang@llvm" + -- + local addon_prefix + if name:startswith("@addon/") then + local rest = name:sub(#"@addon/" + 1) + local pos = rest:find("/", 1, true) + if pos then + addon_prefix = "@addon/" .. rest:sub(1, pos - 1) .. "/" + name = rest:sub(pos + 1) + end + elseif name:startswith("@self/") then + addon_prefix = "@self/" + name = name:sub(#"@self/" + 1) + end + local splitinfo = name:split('@', {plain = true, strict = true}) local toolchain_name = splitinfo[1] if toolchain_name == "" then @@ -707,7 +730,8 @@ function toolchain.parsename(name) end end end - return {name = toolchain_name or packages, packages = packages, requireconfs = requireconfs, requirestr = requirestr} + return {name = toolchain_name or packages, packages = packages, addon_prefix = addon_prefix, + requireconfs = requireconfs, requirestr = requirestr} end -- get toolchain apis @@ -781,9 +805,27 @@ function toolchain.load(name, opt) configs.plat = opt.plat or config.get("plat") or os.host() configs.arch = opt.arch or config.get("arch") or os.arch() + -- find the toolchain script path + -- + -- @note we need to resolve the addon reference before the cache, `@self/` depends on + -- the addon which owns the caller script, and the different addons may provide + -- the same toolchain name + -- + local scriptpath, addon_prefix + if parseinfo.addon_prefix then + -- e.g. set_toolchains("@addon/esp32/xtensa"), set_toolchains("@self/xtensa") + local referenceinfo, errors = addon.resolve_reference(parseinfo.addon_prefix .. name, "/", "toolchains", + {scriptdir = opt.scriptdir}) + if not referenceinfo then + return nil, errors + end + addon_prefix = "@addon/" .. referenceinfo.addon .. "/" + scriptpath = path.join(referenceinfo.dir, referenceinfo.name, "xmake.lua") + end + -- get cache local cache = toolchain._memcache() - local cachekey = toolchain._cachekey(name, configs) + local cachekey = toolchain._cachekey((addon_prefix or "") .. name, configs) -- get it directly from cache dirst local instance = cache:get(cachekey) @@ -791,16 +833,16 @@ function toolchain.load(name, opt) return instance end - -- find the toolchain script path - local scriptpath = nil - for _, dir in ipairs(toolchain.directories()) do - scriptpath = path.join(dir, name, "xmake.lua") - if os.isfile(scriptpath) then - break + if not addon_prefix then + for _, dir in ipairs(toolchain.directories()) do + scriptpath = path.join(dir, name, "xmake.lua") + if os.isfile(scriptpath) then + break + end end end if not scriptpath or not os.isfile(scriptpath) then - return nil, string.format("the toolchain %s not found!", name) + return nil, string.format("the toolchain %s%s not found!", addon_prefix or "", name) end -- get interpreter diff --git a/xmake/languages/c++/xmake.lua b/xmake/languages/c++/xmake.lua index b94a073b8..42ddc2884 100644 --- a/xmake/languages/c++/xmake.lua +++ b/xmake/languages/c++/xmake.lua @@ -60,8 +60,7 @@ language("c++") , "toolchain.sysincludedirs" } , binary = { - "target.runtimes" - , "config.linkdirs" + "config.linkdirs" , "config.frameworkdirs" , "target.linkdirs" , "target.frameworkdirs" @@ -79,13 +78,16 @@ language("c++") , "config.frameworks" , "target.frameworks" , "toolchain.frameworks" + -- runtimes may link libc++.a/libc++abi.a explicitly, so it must come after the + -- object files and user links, but before the syslinks it depends on (e.g. pthread) + -- @see https://github.com/xmake-io/xmake/issues/7442 + , "target.runtimes" , "config.syslinks" , "target.syslinks" , "toolchain.syslinks" } , shared = { - "target.runtimes" - , "config.linkdirs" + "config.linkdirs" , "config.frameworkdirs" , "target.linkdirs" , "target.frameworkdirs" @@ -103,6 +105,8 @@ language("c++") , "config.frameworks" , "target.frameworks" , "toolchain.frameworks" + -- @see https://github.com/xmake-io/xmake/issues/7442 + , "target.runtimes" , "config.syslinks" , "target.syslinks" , "toolchain.syslinks" diff --git a/xmake/languages/c/load.lua b/xmake/languages/c/load.lua index a265f0dbd..7497cc004 100644 --- a/xmake/languages/c/load.lua +++ b/xmake/languages/c/load.lua @@ -61,6 +61,7 @@ function _get_apis() , "package.add_defines" , "package.add_undefines" , "package.add_frameworks" + , "package.add_vectorexts" , "package.add_rpathdirs" , "package.add_linkdirs" , "package.add_includedirs" --@note we need not uses paths for package, see https://github.com/xmake-io/xmake/issues/717 diff --git a/xmake/modules/core/project/depend.lua b/xmake/modules/core/project/depend.lua index 511e6fde6..40d6ba757 100644 --- a/xmake/modules/core/project/depend.lua +++ b/xmake/modules/core/project/depend.lua @@ -167,6 +167,9 @@ function is_changed(dependinfo, opt) end return true elseif deptype == "table" then + if #depvalue ~= #optvalue then + return true + end for subidx, subvalue in ipairs(depvalue) do if subvalue ~= optvalue[subidx] then if _is_show_diagnosis_info() then diff --git a/xmake/modules/core/tools/clang.lua b/xmake/modules/core/tools/clang.lua index 1250d1a46..c264f6656 100644 --- a/xmake/modules/core/tools/clang.lua +++ b/xmake/modules/core/tools/clang.lua @@ -192,6 +192,19 @@ function _has_static_libstdcxx(self) return has_static_libstdcxx end +-- has -nostdlib++? (disable the automatic c++ runtime link, so we can link libc++/libc++abi explicitly) +function _has_nostdlibxx(self) + local has_nostdlibxx = _g._HAS_NOSTDLIBXX + if has_nostdlibxx == nil then + if self:has_flags("-nostdlib++ -Werror", "ldflags", {flagskey = "clang_nostdlibxx"}) then + has_nostdlibxx = true + end + has_nostdlibxx = has_nostdlibxx or false + _g._HAS_NOSTDLIBXX = has_nostdlibxx + end + return has_nostdlibxx +end + -- make the runtime flag -- @see https://github.com/xmake-io/xmake/issues/3546 function nf_runtime(self, runtime, opt) @@ -284,8 +297,36 @@ function nf_runtime(self, runtime, opt) end end end - if runtime:endswith("_static") and _has_static_libstdcxx(self) then - maps["stdc++_static"] = table.join(maps["stdc++_static"], "-static-libstdc++") + if runtime:endswith("_static") then + -- -static-libstdc++ only pulls in libc++.a, not libc++abi.a, so the libc++abi + -- symbols (typeinfo, __cxa_*) stay undefined and the link fails, especially + -- once c++ modules reference more of libc++. + -- + -- if we can locate both static archives, link them explicitly in a group + -- (they reference each other) and disable the driver's automatic c++ runtime + -- with -nostdlib++, otherwise (bundled abi) fall back to -static-libstdc++. + -- + -- note: target.runtimes is ordered right before the syslinks in the c++ link + -- order, so these archives are placed after the object files / user links. + -- @see https://github.com/xmake-io/xmake/issues/7442, https://github.com/xmake-io/xmake/issues/7656 + if llvm_dirs.libcxx_static and llvm_dirs.libcxxabi_static and _has_nostdlibxx(self) then + local cxxlibs = {llvm_dirs.libcxx_static, llvm_dirs.libcxxabi_static} + -- apple ld64 does not support --start-group, it always rescans archives + if not self:is_plat("macosx", "iphoneos", "watchos", "appletvos", "applexros") then + cxxlibs = table.join("-Wl,--start-group", cxxlibs, "-Wl,--end-group") + end + -- -stdlib=libc++ is unused when linking with -nostdlib++, remove it to avoid + -- the `argument unused during compilation` warning + local ldflags = table.remove_if(table.wrap(maps["c++_static"]), function (_, flag) + return flag == "-stdlib=libc++" + end) + maps["c++_static"] = table.join(ldflags, "-nostdlib++", cxxlibs) + elseif _has_static_libstdcxx(self) then + maps["c++_static"] = table.join(maps["c++_static"], "-static-libstdc++") + end + if _has_static_libstdcxx(self) then + maps["stdc++_static"] = table.join(maps["stdc++_static"], "-static-libstdc++") + end end end end diff --git a/xmake/modules/core/tools/ml.lua b/xmake/modules/core/tools/ml.lua index 2e7628cd2..229a7303a 100644 --- a/xmake/modules/core/tools/ml.lua +++ b/xmake/modules/core/tools/ml.lua @@ -35,7 +35,7 @@ function init(self) self:set("mapflags", { -- symbols - ["-g"] = "-Z7" + ["-g"] = "-Zi" , ["-fvisibility=.*"] = "" -- warnings @@ -55,20 +55,14 @@ function init(self) end -- make the symbol flags +-- +-- masm only supports -Zi/-Zd, the -Z7 and -ZI flags of cl.exe are rejected (A4018). +-- -Zi already embeds debug info in the object file (masm has no compile-time pdb), +-- so the "embed" and "edit" levels degrade to it. function nf_symbols(self, levels) - local flags = nil - local values = hashset.from(levels) - if values:has("debug") then - flags = {} - if values:has("edit") then - table.insert(flags, "-ZI") - elseif values:has("embed") then - table.insert(flags, "-Z7") - else - table.insert(flags, "-Zi") - end + if hashset.from(levels):has("debug") then + return {"-Zi"} end - return flags end -- make the warning flag diff --git a/xmake/modules/detect/sdks/find_mingw.lua b/xmake/modules/detect/sdks/find_mingw.lua index c70bebb11..d6d7e0d8e 100644 --- a/xmake/modules/detect/sdks/find_mingw.lua +++ b/xmake/modules/detect/sdks/find_mingw.lua @@ -108,7 +108,8 @@ function _find_mingw(sdkdir, opt) -- find cross toolchain local toolchain = find_cross_toolchain(sdkdir or bindir, {bindir = bindir, cross = cross}) - if not toolchain then -- fallback, e.g. gcc.exe without cross + -- fallback, e.g. gcc.exe without cross + if not toolchain and (is_host("windows") or is_subhost("msys", "cygwin")) then toolchain = find_cross_toolchain(sdkdir or bindir, {bindir = bindir}) end if toolchain then diff --git a/xmake/modules/detect/sdks/find_ndk.lua b/xmake/modules/detect/sdks/find_ndk.lua index ce7a4b712..a89536d5f 100644 --- a/xmake/modules/detect/sdks/find_ndk.lua +++ b/xmake/modules/detect/sdks/find_ndk.lua @@ -95,7 +95,7 @@ function _find_ndk_sdkver(sdkdir, bindir, sysroot, arch) -- try to select the best compatible version local sdkver = "16" if use_llvm or arch == "arm64-v8a" or arch == "riscv64" then - sdkver = (arch == "riscv64") and "35" or "21" + sdkver = (arch == "riscv64") and "36" or "21" end if sysroot then if os.isdir(path.join(sysroot, "usr", "lib", triple, sdkver)) then diff --git a/xmake/modules/detect/tools/find_emar.lua b/xmake/modules/detect/tools/find_emar.lua index 8a6ec2691..138646243 100644 --- a/xmake/modules/detect/tools/find_emar.lua +++ b/xmake/modules/detect/tools/find_emar.lua @@ -83,5 +83,24 @@ function main(opt) end -- find program - return find_program(opt.program or (is_host("windows") and "emar.bat" or "emar"), opt) + -- emsdk 6.0.0+ ships .exe on windows, older releases ship .bat + local program + if opt.program then + program = find_program(opt.program, opt) + else + local candidate_names + if is_host("windows") then + candidate_names = {"emar.exe", "emar.bat"} + else + candidate_names = {"emar"} + end + for _, name in ipairs(candidate_names) do + program = find_program(name, opt) + if program then + break + end + end + end + + return program end diff --git a/xmake/modules/detect/tools/find_emcc.lua b/xmake/modules/detect/tools/find_emcc.lua index e44223d63..dc77b716e 100644 --- a/xmake/modules/detect/tools/find_emcc.lua +++ b/xmake/modules/detect/tools/find_emcc.lua @@ -50,7 +50,24 @@ function main(opt) end -- find program - local program = find_program(opt.program or (is_host("windows") and "emcc.bat" or "emcc"), opt) + -- emsdk 6.0.0+ ships .exe on windows, older releases ship .bat + local program + if opt.program then + program = find_program(opt.program, opt) + else + local candidate_names + if is_host("windows") then + candidate_names = {"emcc.exe", "emcc.bat"} + else + candidate_names = {"emcc"} + end + for _, name in ipairs(candidate_names) do + program = find_program(name, opt) + if program then + break + end + end + end -- find program version local version = nil diff --git a/xmake/modules/detect/tools/find_emrun.lua b/xmake/modules/detect/tools/find_emrun.lua index ac210c4ca..6a96c9d82 100644 --- a/xmake/modules/detect/tools/find_emrun.lua +++ b/xmake/modules/detect/tools/find_emrun.lua @@ -51,9 +51,26 @@ function main(opt) table.insert(paths, emsdk.emscripten) opt.paths = paths end - + -- find program - local program = find_program(opt.program or (is_host("windows") and "emrun.bat" or "emrun"), opt) + -- emsdk 6.0.0+ ships .exe on windows, older releases ship .bat + local program + if opt.program then + program = find_program(opt.program, opt) + else + local candidate_names + if is_host("windows") then + candidate_names = {"emrun.exe", "emrun.bat"} + else + candidate_names = {"emrun"} + end + for _, name in ipairs(candidate_names) do + program = find_program(name, opt) + if program then + break + end + end + end -- find program version local version = nil diff --git a/xmake/modules/detect/tools/find_emxx.lua b/xmake/modules/detect/tools/find_emxx.lua index 4f8cc90ed..6ba454d1d 100644 --- a/xmake/modules/detect/tools/find_emxx.lua +++ b/xmake/modules/detect/tools/find_emxx.lua @@ -50,7 +50,24 @@ function main(opt) end -- find program - local program = find_program(opt.program or (is_host("windows") and "em++.bat" or "em++"), opt) + -- emsdk 6.0.0+ ships .exe on windows, older releases ship .bat + local program + if opt.program then + program = find_program(opt.program, opt) + else + local candidate_names + if is_host("windows") then + candidate_names = {"em++.exe", "em++.bat"} + else + candidate_names = {"em++"} + end + for _, name in ipairs(candidate_names) do + program = find_program(name, opt) + if program then + break + end + end + end -- find program version local version = nil diff --git a/xmake/modules/net/http/download.lua b/xmake/modules/net/http/download.lua index 2695be817..e171c152d 100644 --- a/xmake/modules/net/http/download.lua +++ b/xmake/modules/net/http/download.lua @@ -297,18 +297,8 @@ function _powershell_download(tool, url, outputfile, opt) os.vrunv(tool.program, argv) end --- download url --- --- @param url the input url --- @param outputfile the output file --- @param opt the option, {continue = true} --- --- -function main(url, outputfile, opt) - - -- init output file - opt = opt or {} - outputfile = outputfile or path.filename(url):gsub("%?.+$", "") +-- download url with the first available tool (aria2/curl/wget/powershell) +function _download(url, outputfile, opt) -- attempt to download url using aria2 first (multi-threaded, fastest) local tool = find_tool("aria2", {version = true}) @@ -338,3 +328,62 @@ function main(url, outputfile, opt) assert(tool, "aria2, curl or wget not found!") end + +-- is it a ssl/tls certificate verification error? +function _is_ssl_cert_error(errors) + errors = (errors or ""):lower() + return errors:find("ssl", 1, true) + or errors:find("tls", 1, true) + or errors:find("certificate", 1, true) + or errors:find("handshake", 1, true) +end + +-- download url, and retry once with ssl verification disabled on a certificate error +function _download_fallback(url, outputfile, opt) + local errors + local ok = try + { + function () + _download(url, outputfile, opt) + return true + end, + catch + { + function (errs) + errors = tostring(errs) + end + } + } + if not ok then + if _is_ssl_cert_error(errors) then + wprint("download failed due to ssl certificate verification, retrying with ssl verification disabled ..") + return _download(url, outputfile, table.join(opt, {insecure = true})) + end + raise(errors) + end +end + +-- download url +-- +-- @param url the input url +-- @param outputfile the output file +-- @param opt the option, e.g. {continue = true, insecure = false, insecure_fallback = false} +-- +-- @note if opt.insecure_fallback is enabled and the download fails due to a ssl certificate +-- error, it will retry once with ssl verification disabled. this is only safe when the +-- caller verifies the downloaded file afterwards (e.g. by its sha256 checksum). +-- +function main(url, outputfile, opt) + + -- init output file + opt = opt or {} + outputfile = outputfile or path.filename(url):gsub("%?.+$", "") + + -- download it directly if we do not need the insecure fallback + if opt.insecure or not opt.insecure_fallback then + return _download(url, outputfile, opt) + end + + -- download it with the insecure fallback + return _download_fallback(url, outputfile, opt) +end diff --git a/xmake/modules/package/manager/install_package.lua b/xmake/modules/package/manager/install_package.lua index a2c605ba7..55458ca83 100644 --- a/xmake/modules/package/manager/install_package.lua +++ b/xmake/modules/package/manager/install_package.lua @@ -46,6 +46,8 @@ function _install_package(manager_name, package_name, opt) table.insert(managers, "vcpkg") table.insert(managers, "brew") table.insert(managers, "nix") + elseif is_host("bsd") then + table.insert(managers, "pkg") -- freebsd/dragonflybsd end assert(#managers > 0, "no suitable package manager!") diff --git a/xmake/modules/package/manager/pkg/install_package.lua b/xmake/modules/package/manager/pkg/install_package.lua new file mode 100644 index 000000000..8d04f92b3 --- /dev/null +++ b/xmake/modules/package/manager/pkg/install_package.lua @@ -0,0 +1,62 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file install_package.lua +-- + +-- imports +import("core.base.option") +import("lib.detect.find_tool") +import("privilege.sudo") + +-- install package +-- +-- @param name the package name +-- @param opt the options, e.g. {verbose = true, pkg = "the package name"} +-- +-- @return true or false +-- +function main(name, opt) + + -- init options + opt = opt or {} + + -- find pkg, e.g. freebsd, dragonflybsd + local pkg = find_tool("pkg") + if not pkg then + raise("pkg not found!") + end + + -- init argv + local argv = {"install", "-y", opt.pkg or name} + + -- install package directly if the current user is root + if os.isroot() then + os.vrunv(pkg.program, argv) + -- install with administrator permission? + elseif sudo.has() then + + -- install it if be confirmed + local description = format("try installing %s with administrator permission", name) + local confirm = utils.confirm({default = true, description = description}) + if confirm then + sudo.vrunv(pkg.program, argv) + end + else + raise("cannot get administrator permission!") + end +end diff --git a/xmake/modules/package/manager/vcpkg/find_package.lua b/xmake/modules/package/manager/vcpkg/find_package.lua index 5b515d8a2..0504070a3 100644 --- a/xmake/modules/package/manager/vcpkg/find_package.lua +++ b/xmake/modules/package/manager/vcpkg/find_package.lua @@ -212,7 +212,6 @@ function _find_package(vcpkg, vcpkgdir, name, opt) if required_features then depend_name = name .. "[" .. table.concat(required_features, ",") .. "]" end - local result = nil local argv = {"depend-info", depend_name, "--sort=reverse", "--triplet=" .. triplet} -- pass feature flags to depend-info when in manifest mode, otherwise depend-info will not show the complete dependency tree with features @@ -220,31 +219,44 @@ function _find_package(vcpkg, vcpkgdir, name, opt) table.insert(argv, 1, "--feature-flags=versions") end - local _, dependinfo = try { function () return os.iorunv(vcpkg, argv, manifest_mode and {curdir = opt.installdir} or nil) end } + local _, dependinfo = try { function () return os.iorunv(vcpkg, argv, {curdir = manifest_mode and opt.installdir or vcpkg_utils.classic_curdir()}) end } if manifest_mode and not dependinfo then - -- fallback: newer vcpkg-tool no longer accepts the package name as a positional argument, - -- drop it and retry. see https://github.com/microsoft/vcpkg-tool/pull/1909 + -- fallback: in manifest mode vcpkg rejects the package name as a positional argument, so + -- drop it and query the manifest's dependency tree instead. + -- see https://github.com/microsoft/vcpkg-tool/pull/1909 table.remove(argv, 3) _, dependinfo = try { function () return os.iorunv(vcpkg, argv, {curdir = opt.installdir}) end } end + + -- collect the packages to read info from: always the main package (its .list file was found + -- above, so it is known-installed), plus any transitive dependencies reported by depend-info. + -- this keeps resolution working even when depend-info fails, e.g. a project-owned vcpkg.json + -- puts vcpkg in manifest mode and it rejects arguments; only transitive deps are then missing. + -- @see https://github.com/xmake-io/xmake/issues/7660 + local packagenames = {name} if dependinfo then for _, line in ipairs(dependinfo:split("\n", {plain = true})) do if not line:startswith("vcpkg-") then local packagename = line:match("^([^%[:]+)[^:]*:") if packagename then - local dependencyresult = _get_package_info(packagename, triplet, infodirs, arch, plat, mode) - if dependencyresult then - result = result or {} - for key, dependencylist in pairs(dependencyresult) do - result[key] = result[key] or {} - table.join2(result[key], dependencylist) - end - end + table.insert(packagenames, packagename) end end end end + local result = nil + for _, packagename in ipairs(table.unique(packagenames)) do + local dependencyresult = _get_package_info(packagename, triplet, infodirs, arch, plat, mode) + if dependencyresult then + result = result or {} + for key, dependencylist in pairs(dependencyresult) do + result[key] = result[key] or {} + table.join2(result[key], dependencylist) + end + end + end + -- save version if result then local infoname = path.basename(infofile) diff --git a/xmake/modules/package/manager/vcpkg/install_package.lua b/xmake/modules/package/manager/vcpkg/install_package.lua index a8546e5d0..909374e61 100644 --- a/xmake/modules/package/manager/vcpkg/install_package.lua +++ b/xmake/modules/package/manager/vcpkg/install_package.lua @@ -64,7 +64,10 @@ function _install_for_classic(vcpkg, name, opt) end -- install package - os.vrunv(vcpkg, argv) + -- run in a neutral directory so that a project-owned vcpkg.json in the current working + -- directory does not switch vcpkg into manifest mode (which rejects package arguments). + -- @see https://github.com/xmake-io/xmake/issues/7660 + os.vrunv(vcpkg, argv, {curdir = vcpkg_utils.classic_curdir()}) end -- install for manifest mode diff --git a/xmake/modules/package/manager/vcpkg/utils.lua b/xmake/modules/package/manager/vcpkg/utils.lua index fdd85d501..1c83323b4 100644 --- a/xmake/modules/package/manager/vcpkg/utils.lua +++ b/xmake/modules/package/manager/vcpkg/utils.lua @@ -36,6 +36,22 @@ function need_manifest(opt) end end +-- get a neutral empty directory to run classic-mode vcpkg commands in. +-- +-- vcpkg switches to manifest mode when a vcpkg.json exists in the current working directory, and +-- in manifest mode it rejects individual package arguments ("In manifest mode, `vcpkg install` +-- does not support individual package arguments"). so classic-mode commands (install/list/ +-- depend-info, which pass `<pkg>:<triplet>`) must not run from a project directory that ships its +-- own vcpkg.json. +-- @see https://github.com/xmake-io/xmake/issues/7660 +function classic_curdir() + local dir = path.join(os.tmpdir(), "vcpkg", "classic") + if not os.isdir(dir) then + os.mkdir(dir) + end + return dir +end + function is_installed(vcpkg, name, triplet, opt) local argv = {"list", name .. ":" .. triplet, "--x-full-desc"} local manifest_mode = need_manifest(opt) @@ -46,7 +62,7 @@ function is_installed(vcpkg, name, triplet, opt) end local listinfo = try { function () - return os.iorunv(vcpkg, argv, manifest_mode and {curdir = opt.installdir} or nil) + return os.iorunv(vcpkg, argv, {curdir = manifest_mode and opt.installdir or classic_curdir()}) end} if listinfo then local exact_prefix = name .. ":" .. triplet diff --git a/xmake/modules/package/manager/xmake/search_package.lua b/xmake/modules/package/manager/xmake/search_package.lua index 32991ae3e..a5ed3caf8 100644 --- a/xmake/modules/package/manager/xmake/search_package.lua +++ b/xmake/modules/package/manager/xmake/search_package.lua @@ -23,7 +23,7 @@ import("core.base.semver") import("private.xrepo.quick_search.cache") function _search_package(packages, name, opt) - for _, packageinfo in ipairs(cache.find(name, {description = opt.description ~= false})) do + for _, packageinfo in ipairs(cache.find(name, {description = opt.description ~= false, kind = opt.kind})) do local packagename = packageinfo.name local packagedata = packageinfo.data @@ -59,7 +59,7 @@ end -- search package using the xmake package manager -- -- @param name the package name with pattern --- @param opt the options, e.g. {require_version = "1.x"} +-- @param opt the options, e.g. {require_version = "1.x", kind = "addon"} -- function main(name, opt) opt = opt or {} diff --git a/xmake/modules/package/tools/cmake.lua b/xmake/modules/package/tools/cmake.lua index 360a0f700..311b1c0af 100644 --- a/xmake/modules/package/tools/cmake.lua +++ b/xmake/modules/package/tools/cmake.lua @@ -858,17 +858,32 @@ function _get_envs_for_default_flags(package, configs, opt) return table.clone(_get_default_flags(package, configs, buildtype, opt)) or {} end +-- quote flags that contain whitespace, so they survive as a single argument when cmake expands +-- CMAKE_<LANG>_FLAGS (a space-separated string) onto the compiler/linker command line. +-- e.g. -resource-dir=C:\Program Files\LLVM\lib\clang\22 would otherwise be split at the space. +-- @see https://github.com/xmake-io/xmake/issues/7663 +function _quote_flags_with_spaces(flags) + if flags then + for idx, flag in ipairs(flags) do + if type(flag) == "string" and flag:find("%s") and not flag:startswith("\"") then + flags[idx] = "\"" .. flag .. "\"" + end + end + end + return flags +end + function _get_envs_for_runtime_flags(package, opt) local buildtype = _get_cmake_buildtype(package) local envs = {} local runtimes = package:runtimes() if runtimes then - envs[format("CMAKE_C_FLAGS_%s", buildtype)] = toolchain_utils.map_compflags_for_package(package, "c", "runtime", runtimes) - envs[format("CMAKE_CXX_FLAGS_%s", buildtype)] = toolchain_utils.map_compflags_for_package(package, "cxx", "runtime", runtimes) - envs[format("CMAKE_EXE_LINKER_FLAGS_%s", buildtype)] = toolchain_utils.map_linkflags_for_package(package, "binary", {"cxx"}, "runtime", runtimes) - envs[format("CMAKE_STATIC_LINKER_FLAGS_%s", buildtype)] = toolchain_utils.map_linkflags_for_package(package, "static", {"cxx"}, "runtime", runtimes) - envs[format("CMAKE_SHARED_LINKER_FLAGS_%s", buildtype)] = toolchain_utils.map_linkflags_for_package(package, "shared", {"cxx"}, "runtime", runtimes) - envs[format("CMAKE_MODULE_LINKER_FLAGS_%s", buildtype)] = toolchain_utils.map_linkflags_for_package(package, "shared", {"cxx"}, "runtime", runtimes) + envs[format("CMAKE_C_FLAGS_%s", buildtype)] = _quote_flags_with_spaces(toolchain_utils.map_compflags_for_package(package, "c", "runtime", runtimes)) + envs[format("CMAKE_CXX_FLAGS_%s", buildtype)] = _quote_flags_with_spaces(toolchain_utils.map_compflags_for_package(package, "cxx", "runtime", runtimes)) + envs[format("CMAKE_EXE_LINKER_FLAGS_%s", buildtype)] = _quote_flags_with_spaces(toolchain_utils.map_linkflags_for_package(package, "binary", {"cxx"}, "runtime", runtimes)) + envs[format("CMAKE_STATIC_LINKER_FLAGS_%s", buildtype)] = _quote_flags_with_spaces(toolchain_utils.map_linkflags_for_package(package, "static", {"cxx"}, "runtime", runtimes)) + envs[format("CMAKE_SHARED_LINKER_FLAGS_%s", buildtype)] = _quote_flags_with_spaces(toolchain_utils.map_linkflags_for_package(package, "shared", {"cxx"}, "runtime", runtimes)) + envs[format("CMAKE_MODULE_LINKER_FLAGS_%s", buildtype)] = _quote_flags_with_spaces(toolchain_utils.map_linkflags_for_package(package, "shared", {"cxx"}, "runtime", runtimes)) end return envs end @@ -1285,8 +1300,11 @@ function _shrink_cmake_arguments(argv, oldir, opt) shrink = true return true end]] - -- shrink long arguments - if #v > 128 then + -- shrink long arguments, or arguments that carry quoted flags (e.g. a path with spaces). + -- routing them through set() in CMakeLists.txt keeps the embedded quotes intact, instead + -- of relying on the fragile multi-layer quoting of passing -D...="..." on the cmake cli. + -- @see https://github.com/xmake-io/xmake/issues/7663 + if #v > 128 or v:find("\"", 1, true) then local flags = v:replace("\"", "\\\"") table.insert(cmake_argv, ("set(%s \"%s\")"):format(k, flags)) shrink = true diff --git a/xmake/modules/package/tools/xmake.lua b/xmake/modules/package/tools/xmake.lua index 4efee0974..305074df0 100644 --- a/xmake/modules/package/tools/xmake.lua +++ b/xmake/modules/package/tools/xmake.lua @@ -283,6 +283,14 @@ function _get_configs(package, configs, opt) if not package:use_external_includes() and (not policies or not policies:find("package.include_external_headers", 1, true)) then table.insert(policies_list, "package.include_external_headers:n") end + -- the sub-process must install its packages locally too, otherwise they go to the + -- global directory while we expect them under our build directory, + -- @see https://github.com/xmake-io/xmake/issues/7716 + for _, policyname in ipairs({"package.install_locally", "package.host.install_locally"}) do + if project.policy(policyname) and (not policies or not policies:find(policyname, 1, true)) then + table.insert(policies_list, policyname) + end + end if policies and policies:find("package.build.ccache", 1, true) then table.insert(configs, "--ccachedir=" .. path.join(path.directory(package:cachedir()), "build_cache")) table.insert(policies_list, "build.ccache") @@ -527,14 +535,19 @@ function install(package, configs, opt) -- get build environments local envs = opt.envs or buildenvs(package) - -- if the package is installed locally, pass the local packages directory - -- to the child xmake process so it can find already-installed deps - -- without re-installing them to the global directory + -- if the package is installed locally, pass our local packages directory to the + -- child xmake process, so the packages it installs locally land in the same place + -- and the deps we have already installed are found instead of installed again + -- + -- @note we must not override `XMAKE_PKG_INSTALLDIR` here: it is the *global* root + -- of the child, and overriding it hides `~/.xmake/packages` from it, so the host + -- packages it needs (e.g. the toolchains) would be installed again under our + -- build directory, @see https://github.com/xmake-io/xmake/issues/7716 + -- -- @see https://github.com/xmake-io/xmake/discussions/7441 if package:is_local() and not package:is_source_embed() then envs = table.clone(envs) - envs.XMAKE_PKG_INSTALLDIR = package_core.installdir({localdir = true}) - envs.XMAKE_PKG_CACHEDIR = package_core.cachedir({localdir = true}) + envs.XMAKE_PKG_LOCALDIR = package_core.installdir({localdir = true}) end -- pass local repositories diff --git a/xmake/modules/private/action/addon/impl/install_addons.lua b/xmake/modules/private/action/addon/impl/install_addons.lua new file mode 100644 index 000000000..4cc5b0fba --- /dev/null +++ b/xmake/modules/private/action/addon/impl/install_addons.lua @@ -0,0 +1,142 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file install_addons.lua +-- + +-- imports +import("core.package.addon") +import("core.project.addons") +import("private.action.addon.impl.xrepo", {alias = "xrepo_addon"}) + +-- get the requires of the declared addons +-- +-- @note we install the locked versions, but the declaration is authoritative, so we +-- resolve them again if the user has changed it or upgrades them +-- +function _get_requires(declared, locked) + local requires = {} + for _, requirestr in ipairs(declared) do + local name = addons.requirename(requirestr) + local lockinfo = locked and locked[name] + if addons.locked_valid(requirestr, lockinfo) then + requirestr = name .. " " .. lockinfo.version + end + table.insert(requires, requirestr) + end + return requires +end + +-- lock the installed addons, so that we always get the same ones +-- +-- @note we get the installed versions from the addons registry, they are +-- registered when installing them, @see core/package/addon.lua +-- +function _lock_addons(projectdir, declared) + local lockinfo = {} + local locked = addons.locked(projectdir) or {} + + -- @note we need to reload the registry, they have been installed by another process, + -- and we must not see them through the locked versions, we are locking them right now, + -- e.g. `xmake addon --upgrade` pins the old ones before loading this project + local installed = addon.addons({force = true, unpinned = true}) + for _, requirestr in ipairs(declared) do + local name = addons.requirename(requirestr) + local addoninfo = assert(installed[addon.dirname(name)], "addon(%s) is not installed!", name) + local oldversion = locked[name] and locked[name].version + if oldversion and oldversion ~= addoninfo.version then + cprint("${color.success}upgrade ${bright}%s${clear}: %s -> %s", name, oldversion, addoninfo.version) + end + -- we lock the repository too, so that the other users get it from the same source, + -- @see xmake/modules/private/action/require/impl/lock_packages.lua + lockinfo[name] = {version = addoninfo.version, repo = addoninfo.repo} + end + lockinfo.__meta__ = {version = addons.lockfile_version()} + + -- @note we need to write it deterministically, the key order of a lua table is random, + -- otherwise the lock file would change even if nothing changed, + -- @see xmake/modules/private/action/require/impl/lock_packages.lua + local content = string.serialize(lockinfo, {orderkeys = true}) + local tmpfile = os.tmpfile() + io.writefile(tmpfile, content, {encoding = "binary"}) + + -- and we only write it if the content is different, so we can keep the file time + os.cp(tmpfile, addons.lockfile(projectdir), {copy_if_different = true}) + os.rm(tmpfile) +end + +-- install the addons which a project declares, e.g. add_addons("esp32-devel 1.0.x") +-- +-- @note we are also called from a sub-process, the project cannot be loaded until +-- its addons are installed, @see core/project/project.lua +-- +-- install the addons which a project declares, e.g. add_addons("esp32-devel 1.0.x") +-- +-- @param projectdir the project directory, we only read/write its lock file here +-- @param datafile the declarations of the project, {addons = {...}, repositories = {...}} +-- +-- @note we are always run in a working directory which has no project, we cannot load +-- the project again here, @see xmake/core/project/project.lua +-- +function main(projectdir, datafile, opt) + opt = opt or {} + projectdir = projectdir or os.projectdir() + local declarations = type(datafile) == "table" and datafile or io.load(datafile) + local declared = table.wrap(declarations and declarations.addons) + if #declared == 0 then + return + end + + -- upgrade them? we need to resolve the declared versions again + local locked = not opt.upgrade and addons.locked(projectdir) or nil + + -- this project declares its own repositories? we pass them to xrepo, + -- they are only used by this installation, we do not register them globally + local rcfile + local repositories = table.wrap(declarations.repositories) + if #repositories > 0 then + rcfile = os.tmpfile() .. ".lua" + local file = io.open(rcfile, "w") + for _, repo in ipairs(repositories) do + file:print("add_repositories(%q)", repo) + end + file:close() + end + + -- install them with xrepo, it installs the packages in its own working directory + try + { + function () + xrepo_addon("install", _get_requires(declared, locked), {includes = rcfile}) + end, + finally + { + -- @note try() swallows the errors if we do not re-raise them here + function (ok, errors) + if rcfile then + os.tryrm(rcfile) + end + if not ok then + raise(errors) + end + end + } + } + + -- and lock them, so that the other users get the same versions + _lock_addons(projectdir, declared) +end diff --git a/xmake/modules/private/action/addon/impl/xrepo.lua b/xmake/modules/private/action/addon/impl/xrepo.lua new file mode 100644 index 000000000..46ada2d01 --- /dev/null +++ b/xmake/modules/private/action/addon/impl/xrepo.lua @@ -0,0 +1,57 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file xrepo.lua +-- + +-- imports +import("core.base.option") +import("core.package.addon") + +-- run the given xrepo action for the addons +-- +-- @note xrepo installs the packages in its own working project, so it works anywhere, +-- and we need not implement the download/dependencies/confirm logic again +-- +-- @param action the action name, e.g. "install", "search" +-- @param names the addon names, urls or require strings, e.g. {"esp32-devel 1.0.x"} +-- @param opt the options, e.g. {force = true, includes = "/tmp/xxx.lua"} +-- +-- @note we always run it in a working directory which has no project, @see addon.workdir() +-- +function main(action, names, opt) + opt = opt or {} + local argv = {"lua", "private.xrepo", action, "--addon"} + + -- we need to pass the common options to the sub-process, e.g. -y, -v, -D + for _, name in ipairs({"yes", "verbose", "diagnosis"}) do + if option.get(name) then + table.insert(argv, "--" .. name) + end + end + if opt.force then + table.insert(argv, "--force") + end + + -- the extra lua configuration files, e.g. the repositories which a project declares + if opt.includes then + table.insert(argv, "--includes=" .. opt.includes) + end + + table.join2(argv, names) + os.execv(os.programfile(), argv, {curdir = opt.curdir or addon.workdir()}) +end diff --git a/xmake/modules/private/action/build/pcheader.lua b/xmake/modules/private/action/build/pcheader.lua index 4e984f62b..1682ead8c 100644 --- a/xmake/modules/private/action/build/pcheader.lua +++ b/xmake/modules/private/action/build/pcheader.lua @@ -38,12 +38,24 @@ function config(target, langkind, opt) -- https://github.com/xmake-io/xmake/issues/2667 -- https://github.com/xmake-io/xmake/issues/5858 if not os.isfile(headerfile) then - io.writefile(headerfile, ([[ + local langcxx = (langkind == "cxx" or langkind == "mxx") + local content + if langcxx then + content = [[ #pragma system_header #ifdef __cplusplus #include "%s" #endif // __cplusplus - ]]):format(path.absolute(pcheaderfile):gsub("\\", "/"))) + ]] + else + content = [[ +#pragma system_header +#ifndef __cplusplus +#include "%s" +#endif + ]] + end + io.writefile(headerfile, content:format(path.absolute(pcheaderfile):gsub("\\", "/"))) end -- we need only to add a header wrapper in .gch directory -- @see https://github.com/xmake-io/xmake/issues/5858#issuecomment-2506918167 diff --git a/xmake/modules/private/action/require/impl/actions/download.lua b/xmake/modules/private/action/require/impl/actions/download.lua index 55e43a3db..a8846f97b 100644 --- a/xmake/modules/private/action/require/impl/actions/download.lua +++ b/xmake/modules/private/action/require/impl/actions/download.lua @@ -216,6 +216,7 @@ function _download(package, url, sourcedir, opt) else http.download(url, packagefile, { insecure = global.get("insecure-ssl"), + insecure_fallback = true, -- retry without ssl verification on cert error, the file is verified by sha256 below headers = opt.url_http_headers or package:policy("package.download.http_headers")}) end end diff --git a/xmake/modules/private/action/require/impl/actions/download_resources.lua b/xmake/modules/private/action/require/impl/actions/download_resources.lua index c185d25b0..dffa742b2 100644 --- a/xmake/modules/private/action/require/impl/actions/download_resources.lua +++ b/xmake/modules/private/action/require/impl/actions/download_resources.lua @@ -118,6 +118,7 @@ function _download(package, resource_name, resource_url, resource_hash) elseif resource_url:find(string.ipattern("https-://")) or resource_url:find(string.ipattern("ftps-://")) then http.download(resource_url, resource_file, { insecure = global.get("insecure-ssl"), + insecure_fallback = true, -- retry without ssl verification on cert error, the file is verified by sha256 below headers = package:policy("package.download.http_headers")}) else raise("invalid resource url(%s)", resource_url) diff --git a/xmake/modules/private/action/require/impl/actions/install.lua b/xmake/modules/private/action/require/impl/actions/install.lua index 7fb54a951..c07add337 100644 --- a/xmake/modules/private/action/require/impl/actions/install.lua +++ b/xmake/modules/private/action/require/impl/actions/install.lua @@ -22,6 +22,7 @@ import("core.base.option") import("core.base.tty") import("core.package.package", {alias = "core_package"}) +import("core.package.addon") import("core.project.target") import("core.project.project") import("core.platform.platform") @@ -283,6 +284,50 @@ function _merge_staticlibs(package) end end +-- register the installed addon, so that xmake can find its payloads, e.g. plugins +-- +-- @note the addon manifest(addon.lua) is only read when installing it, everything which +-- is needed later is recorded in the addons registry, @see core/package/addon.lua +-- +function _register_addon(package) + + -- get the addon deps from the package recipe + local deps + for _, dep in ipairs(package:plaindeps() or {}) do + if dep:is_addon() then + deps = deps or {} + table.insert(deps, dep:name()) + end + end + + -- the addon describes itself? we prefer its own description + -- + -- @note the deps are duplicated in its manifest, but the recipe is authoritative, + -- xmake needs them before downloading the addon sources, so we only report the + -- mismatch, they must be kept in sync + -- + local description = package:description() + local manifest = package:data("addon.manifest") + if manifest then + description = manifest.description or description + for _, dep in ipairs(manifest.deps) do + if not (deps and table.contains(deps, dep)) then + wprint("addon(%s): dep(%s) is declared in its manifest, but not in the package recipe!", + package:name(), dep) + end + end + end + + -- we also record where it comes from, so that the projects can lock it, + -- @see xmake/modules/private/action/addon/impl/install_addons.lua + local repo = package:repo() + addon.register(package:name(), package:version_str() or "latest", + {description = description, deps = deps, + repo = repo and {url = repo:url(), commit = repo:commit(), branch = repo:branch()} or nil, + manifest_deps = manifest and manifest.deps or nil, + globalmodules = manifest and #manifest.globalmodules > 0 and manifest.globalmodules or nil}) +end + -- get failed install directory function _get_installdir_failed(package) return path.join(package:cachedir(), "installdir.failed") @@ -499,6 +544,11 @@ function main(package) -- save the package info to the manifest file package:manifest_save() + + -- register this addon, so that xmake can find its payloads, e.g. plugins + if package:is_addon() then + _register_addon(package) + end installed_now = true end end @@ -568,6 +618,13 @@ function main(package) end os.tryrm(installdir) + -- the addon is registered before testing it, its `on_test` needs to use it, + -- e.g. xmake create -t esp32.blink, so we need to unregister it again here, + -- otherwise it would be seen as installed while its files are gone + if package:is_addon() then + addon.unregister(package:name(), package:version_str() or "latest") + end + -- is not last scheme? we can fallback to next scheme and try reinstall it again local current_scheme = package:current_scheme() local schemes_orderlist = package:schemes_orderlist() diff --git a/xmake/modules/private/action/require/impl/actions/patch_sources.lua b/xmake/modules/private/action/require/impl/actions/patch_sources.lua index 6c18b69b1..6b8e60e59 100644 --- a/xmake/modules/private/action/require/impl/actions/patch_sources.lua +++ b/xmake/modules/private/action/require/impl/actions/patch_sources.lua @@ -80,6 +80,7 @@ function _patch(package, patchinfo) if patch_url:find(string.ipattern("https-://")) or patch_url:find(string.ipattern("ftps-://")) then http.download(patch_url, patch_file, { insecure = global.get("insecure-ssl"), + insecure_fallback = true, -- retry without ssl verification on cert error, the file is verified by sha256 below headers = package:policy("package.download.http_headers")}) else -- copy the patch file diff --git a/xmake/modules/private/action/require/impl/install_packages.lua b/xmake/modules/private/action/require/impl/install_packages.lua index f0da9eb2e..2d633109e 100644 --- a/xmake/modules/private/action/require/impl/install_packages.lua +++ b/xmake/modules/private/action/require/impl/install_packages.lua @@ -167,6 +167,13 @@ function _get_confirm_from_3rd(packages) end -- get user confirm +-- +-- @param packages the packages to be installed +-- @param opt the options +-- - toolchain: these packages are toolchain packages, we will show a different tip for it +-- +-- @return the confirm result and the modified packages +-- function _get_confirm(packages, opt) opt = opt or {} @@ -204,6 +211,8 @@ function _get_confirm(packages, opt) -- show tips if opt.toolchain then cprint("${bright color.warning}note: ${clear}install or modify (m) these ${bright}toolchain${clear} packages first (pass -y to skip confirm)?") + elseif opt.packagekind == "addon" then + cprint("${bright color.warning}note: ${clear}install or modify (m) these ${bright}addons${clear} (pass -y to skip confirm)?") else cprint("${bright color.warning}note: ${clear}install or modify (m) these packages (pass -y to skip confirm)?") end @@ -683,6 +692,11 @@ function _get_package_installdeps(packages) end -- install packages +-- +-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"} +-- @param opt the options, @see main +-- - toolchain: only install the toolchain packages and their dependent packages +-- function _install_packages(requires, opt) opt = opt or {} @@ -845,8 +859,15 @@ end -- install all required packages -- --- @param requires the requires table --- @param opt the options +-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"} +-- @param opt the options, it will be passed to `package.load_packages` directly +-- - requires_extra: the extra require configs from `add_requires()`, indexed by the require string +-- - nodeps: only install the given packages, do not install their dependent packages +-- - system: load package from system if `true`, and never load it if `false` (only for non-3rd packages) +-- - packagekind: the package kind, e.g. "addon", it will be loaded from the `addons` root directory of repositories +-- @note `toolchain` is reserved and it will be set internally, @see load_packages +-- +-- @return the installed packages, including the toolchain packages and all dependent packages -- function main(requires, opt) -- we need to install toolchain packages first, diff --git a/xmake/modules/private/action/require/impl/package.lua b/xmake/modules/private/action/require/impl/package.lua index 3ad758c3a..1105384c8 100644 --- a/xmake/modules/private/action/require/impl/package.lua +++ b/xmake/modules/private/action/require/impl/package.lua @@ -43,6 +43,15 @@ function _memcache() end -- load require info +-- +-- @param require_str the require string, e.g. "zlib >=1.2.11", "libplist[shared,debug]" +-- @param requires_extra the extra require configs from `add_requires()`, indexed by the require string +-- @param opt the options +-- - requirepath: the parent require path, e.g. "foo.bar", it's used to get the resolved requireinfo +-- - resolvedinfo: the resolved requireinfo of dependency conflicts, indexed by require path +-- +-- @return the package name and requireinfo +-- function _load_require(require_str, requires_extra, opt) opt = opt or {} @@ -183,6 +192,15 @@ function _load_package_from_project(packagename) end -- load package package from repositories +-- +-- @param packagename the package name +-- @param opt the options +-- - plat: the given platform of this package +-- - arch: the given architecture of this package +-- - name: the given repository name, we will only find this package in the given repository +-- - rootdir: the root directory of repositories, e.g. "packages" (default), "addons" +-- - locked_repo: the locked repository info in `xmake-requires.lock`, e.g. {url = .., commit = .., branch = ..} +-- function _load_package_from_repository(packagename, opt) opt = opt or {} local packagedir, repo = repository.packagedir(packagename, opt) @@ -191,7 +209,31 @@ function _load_package_from_repository(packagename, opt) end end +-- get the root directory of repositories for the given package +-- +-- e.g. "packages" (default), "addons", "plugins" (deprecated) +-- +-- @note the addon packages are only searched from the `addons` root directory, +-- and we need to set it explicitly, e.g. add_deps("foo", {kind = "addon"}) +-- +function _get_repository_rootdir(requireinfo, opt) + local packagekind = requireinfo.kind or opt.packagekind + if packagekind == "addon" then + return "addons" + elseif packagekind == "plugin" then + return "plugins" + end + return "packages" +end + -- load package package from base +-- +-- e.g. package("foo") set_base("bar") +-- +-- @param package the package instance +-- @param basename the base package name +-- @param opt the options, @see _load_package_from_repository +-- function _load_package_from_base(package, basename, opt) local package_base = _load_package_from_project(basename) if not package_base then @@ -203,6 +245,10 @@ function _load_package_from_base(package, basename, opt) end -- has locked requires? +-- +-- @param opt the options +-- - force: force to use the locked requires even if `xmake require --upgrade` is called +-- function _has_locked_requires(opt) opt = opt or {} if not option.get("upgrade") or opt.force then @@ -211,6 +257,13 @@ function _has_locked_requires(opt) end -- get locked requires +-- +-- @param requirekey the require key in `xmake-requires.lock`, @see _get_packagelock_key +-- @param opt the options +-- - force: force to reload `xmake-requires.lock` and ignore `--upgrade` +-- +-- @return the locked requireinfo and the version of `xmake-requires.lock` +-- function _get_locked_requires(requirekey, opt) opt = opt or {} local requireslock = _memcache():get("requireslock") @@ -260,6 +313,10 @@ end -- -- orderdeps: a -> b -> c -- +-- @param package the package instance +-- @param opt the options +-- - private: also sort the private library deps, e.g. add_deps("foo", {private = true}) +-- function _sort_librarydeps(package, opt) -- we must use native deps list instead of package:deps() to generate correct link order local orderdeps = {} @@ -564,6 +621,13 @@ function _match_requirepath(requirepath, requireconf) end -- init requireinfo +-- +-- @param requireinfo the requireinfo +-- @param package the package instance +-- @param opt the options +-- - is_toplevel: this package is a toplevel package in `add_requires()`, but not a dependent package, +-- and we will pass some root configs to it, e.g. toolchains, runtimes, lto, asan .. +-- function _init_requireinfo(requireinfo, package, opt) -- pass root configs to top library package requireinfo.configs = requireinfo.configs or {} @@ -899,11 +963,35 @@ function _select_package_runtimes(package) end end --- load required packages +-- load the given required package +-- +-- we will load it from the project, repositories and system in order, +-- and the requireinfo will be initialized and attached to the package instance. +-- +-- @param packagename the package name, e.g. "zlib", "zlib~debug", "vcpkg::zlib" +-- @param requireinfo the requireinfo, @see _load_require +-- @param opt the options +-- - system: load package from system if `true`, and never load it if `false`, +-- it's only used when `add_requires("zlib", {system = nil})` is not set (only for non-3rd packages) +-- - packagekind: the package kind, e.g. "addon", it will be loaded from the `addons` root directory of repositories +-- - toolchain: only load toolchain packages, the non-toolchain toplevel packages will be ignored +-- - requirepath: the current require path, e.g. "foo.bar", it's used to detect circular dependencies +-- and match `add_requireconfs()` +-- - parentinfo: the parent requireinfo, this package will inherit some builtin configs from it, e.g. runtimes, pic +-- +-- @return the package instance, it will be nil if this package is filtered by `opt.toolchain`, +-- and it will raise an error if this package is not found in any repositories +-- function _load_package(packagename, requireinfo, opt) -- check circular dependency opt = opt or {} + + -- the `addon` and `self` names are reserved, we use them to reference the addon resources, + -- e.g. add_rules("@addon/esp32/flash"), import("@self.sdkconfig") + if packagename == "addon" or packagename == "self" then + raise("package(%s): the name `%s` is reserved by xmake for the addon references, please rename it!", packagename, packagename) + end if opt.requirepath then local splitinfo = opt.requirepath:split(".", {plain = true}) if #splitinfo > 3 and @@ -949,6 +1037,7 @@ function _load_package(packagename, requireinfo, opt) plat = requireinfo.plat, arch = requireinfo.arch, name = requireinfo.reponame, + rootdir = _get_repository_rootdir(requireinfo, opt), locked_repo = locked_requireinfo and locked_requireinfo.repo}) if package then from_repo = true @@ -958,7 +1047,9 @@ function _load_package(packagename, requireinfo, opt) -- load base package if package and package:get("base") then _load_package_from_base(package, package:get("base"), { - name = requireinfo.reponame, locked_repo = locked_requireinfo and locked_requireinfo.repo}) + name = requireinfo.reponame, + rootdir = _get_repository_rootdir(requireinfo, opt), + locked_repo = locked_requireinfo and locked_requireinfo.repo}) end -- load package from system @@ -1105,7 +1196,14 @@ function _load_package(packagename, requireinfo, opt) return package end --- load all required packages +-- load all required packages and their dependent packages +-- +-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"} +-- @param opt the options, @see load_packages +-- +-- @return the packages with all dependent packages (the deps are always in front of their parents), +-- and the packages without deps +-- function _load_packages(requires, opt) -- no requires? @@ -1420,6 +1518,11 @@ end -- compatible with all previous link dependencies? -- @see https://github.com/xmake-io/xmake/issues/2719 +-- +-- @param package the package instance +-- @param opt the options +-- - install_finished: the installation has been finished, we do not need to check compatibility again +-- function _compatible_with_previous_librarydeps(package, opt) -- skip to check compatibility if installation has been finished @@ -1524,6 +1627,13 @@ function cachedir() end -- this package should be install? +-- +-- @param package the package instance +-- @param opt the options +-- - install_finished: the installation has been finished, it's used to check if this package +-- has been installed successfully, and we will ignore `package.install_always` +-- policy and the librarydeps compatibility checking +-- function should_install(package, opt) opt = opt or {} if package:is_template() then @@ -1592,6 +1702,9 @@ function get_configs_str(package) end if requireinfo.kind then table.insert(configs, requireinfo.kind) + elseif package:is_addon() then + -- @note the kind is only set for the dependencies, e.g. add_deps("foo", {kind = "addon"}) + table.insert(configs, "addon") end local ignored_configs_for_buildhash = hashset.from(requireinfo.ignored_configs_for_buildhash or {}) local configs_overrided = requireinfo.configs_overrided or {} @@ -1631,7 +1744,15 @@ function get_configs_str(package) return configs_str end --- get locked requireinfo +-- get locked requireinfo from `xmake-requires.lock` +-- +-- @param requireinfo the requireinfo, it must contain the requirekey +-- @param opt the options +-- - force: force to reload `xmake-requires.lock` and ignore `--upgrade` +-- +-- @return the locked requireinfo and the version of `xmake-requires.lock`, +-- it will be nil if the lock file does not exist or its version is incompatible +-- function get_locked_requireinfo(requireinfo, opt) local requirekey = requireinfo.requirekey local locked_requireinfo, requireslock_version @@ -1645,6 +1766,13 @@ function get_locked_requireinfo(requireinfo, opt) end -- load requires +-- +-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"} +-- @param requires_extra the extra require configs from `add_requires()`, indexed by the require string +-- @param opt the options, @see _load_require +-- +-- @return the require items, e.g. {{name = "zlib", info = {version = ">=1.2.11", ..}}, ..} +-- function load_requires(requires, requires_extra, opt) opt = opt or {} local requireitems = {} @@ -1656,6 +1784,18 @@ function load_requires(requires, requires_extra, opt) end -- load all required packages +-- +-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"} +-- @param opt the options +-- - requires_extra: the extra require configs from `add_requires()`, e.g. {["zlib >=1.2.11"] = {configs = {shared = true}}} +-- - nodeps: only load the given packages, do not load their dependent packages +-- - system: load package from system if `true`, and never load it if `false` (only for non-3rd packages) +-- - packagekind: the package kind, e.g. "addon", it will be loaded from the `addons` root directory of repositories +-- - toolchain: only load toolchain packages and their dependent packages +-- - requirepath: the parent require path, e.g. "foo.bar", it's used to detect circular dependencies and match `add_requireconfs()` +-- - parentinfo: the parent requireinfo, the child package will inherit some builtin configs from it, e.g. runtimes, pic +-- - resolvedinfo: the resolved requireinfo of dependency conflicts, it's only used to reload packages internally +-- function load_packages(requires, opt) opt = opt or {} local unique = {} diff --git a/xmake/modules/private/action/require/impl/repository.lua b/xmake/modules/private/action/require/impl/repository.lua index 3df59c42c..d17bdb570 100644 --- a/xmake/modules/private/action/require/impl/repository.lua +++ b/xmake/modules/private/action/require/impl/repository.lua @@ -151,6 +151,9 @@ function pulled() end -- get package directory from repositories +-- +-- @param packagename the package name +-- @param opt {rootdir = "packages|addons|plugins"} function packagedir(packagename, opt) -- strip trailing ~tag, e.g. zlib~debug @@ -162,7 +165,8 @@ function packagedir(packagename, opt) -- get cache key local reponame = opt.name - local cachekey = packagename + local rootdir = opt.rootdir or "packages" + local cachekey = rootdir .. "/" .. packagename local locked_repo = opt.locked_repo if locked_repo then cachekey = cachekey .. locked_repo.url .. (locked_repo.commit or "") .. (locked_repo.branch or "") @@ -185,7 +189,7 @@ function packagedir(packagename, opt) -- find the package directory from repositories if not foundir then for _, repo in ipairs(repositories()) do - local dir = path.join(repo:directory(), "packages", packagename:sub(1, 1), packagename) + local dir = path.join(repo:directory(), rootdir, packagename:sub(1, 1), packagename) if os.isdir(dir) and os.isfile(path.join(dir, "xmake.lua")) and (not reponame or reponame == repo:name()) then foundir = {dir, repo} break diff --git a/xmake/modules/private/action/require/install.lua b/xmake/modules/private/action/require/install.lua index b7ba9ef5e..ebc648124 100644 --- a/xmake/modules/private/action/require/install.lua +++ b/xmake/modules/private/action/require/install.lua @@ -82,7 +82,14 @@ function main(requires_raw) -- install packages environment.enter() - local packages = install_packages(requires, {requires_extra = requires_extra}) + -- @note the `--plugin` option is deprecated, please use `--addon` instead + local packagekind = "package" + if option.get("addon") then + packagekind = "addon" + elseif option.get("plugin") then + packagekind = "plugin" + end + local packages = install_packages(requires, {packagekind = packagekind, requires_extra = requires_extra}) if packages then _check_missing_packages(packages) end diff --git a/xmake/modules/private/action/require/search.lua b/xmake/modules/private/action/require/search.lua index e714c6c19..a0f98e0d9 100644 --- a/xmake/modules/private/action/require/search.lua +++ b/xmake/modules/private/action/require/search.lua @@ -20,6 +20,7 @@ -- imports import("core.base.task") +import("core.base.option") import("private.action.require.impl.utils.filter") import("private.action.require.impl.repository") import("private.action.require.impl.environment") @@ -41,11 +42,14 @@ function main(names) task.run("repo", {update = true}) end + -- we only search the addon packages if `--addon` is enabled + local kind = option.get("addon") and "addon" or nil + -- show title - print("The package names:") + print(kind == "addon" and "The addon names:" or "The package names:") -- search packages - for name, packages in pairs(search_packages(names)) do + for name, packages in pairs(search_packages(names, {kind = kind})) do if #packages > 0 then -- show name diff --git a/xmake/modules/private/check/checkers/api/package/kind.lua b/xmake/modules/private/check/checkers/api/package/kind.lua index 4a9c309e3..2e4f2495b 100644 --- a/xmake/modules/private/check/checkers/api/package/kind.lua +++ b/xmake/modules/private/check/checkers/api/package/kind.lua @@ -37,6 +37,8 @@ function main(opt) end return true end - return value == "binary" or value == "toolchain" or value == "template" + -- @note the `plugin` kind is deprecated, please use the `addon` kind instead + return value == "binary" or value == "toolchain" or value == "template" or + value == "addon" or value == "plugin" end})) end diff --git a/xmake/modules/private/utils/batchcmds.lua b/xmake/modules/private/utils/batchcmds.lua index 3f584b286..349e31efe 100644 --- a/xmake/modules/private/utils/batchcmds.lua +++ b/xmake/modules/private/utils/batchcmds.lua @@ -28,6 +28,7 @@ import("core.theme.theme") import("core.tool.linker") import("core.tool.compiler") import("core.language.language") +import("core.sandbox.sandbox") import("utils.run_script") import("utils.progress", {alias = "progress_utils"}) import("utils.binary.rpath", {alias = "rpath_utils"}) @@ -126,6 +127,20 @@ function _runcmd_vlua(cmd, opt) end end +-- run command: call +function _runcmd_call(cmd, opt) + local func = cmd.func + if func then + if not opt.dryrun then + local argv = table.clone(cmd.argv) + if cmd.opt then + table.insert(argv, cmd.opt) + end + func(table.unpack(argv)) + end + end +end + -- run command: os.mkdir function _runcmd_mkdir(cmd, opt) local dir = cmd.dir @@ -222,6 +237,7 @@ function _runcmd(cmd, opt) vexecv = _runcmd_vexecv, lua = _runcmd_lua, vlua = _runcmd_vlua, + call = _runcmd_call, mkdir = _runcmd_mkdir, rmdir = _runcmd_rmdir, cd = _runcmd_cd, @@ -305,11 +321,23 @@ function batchcmds:lua(script, argv, opt) table.insert(self:cmds(), {kind = "lua", script = script, argv = argv, opt = opt}) end --- add command: run lua script file, command or module +-- add command: run lua script, command or module function batchcmds:vlua(script, argv, opt) table.insert(self:cmds(), {kind = "vlua", script = script, argv = argv, opt = opt}) end +-- add command: call lua function +function batchcmds:call(func, argv, opt) + local functype = type(func) + if functype == "string" then + self:lua(func, argv, opt) + else + assert(functype == "function") + sandbox.fork(func) + table.insert(self:cmds(), {kind = "call", func = func, argv = argv, opt = opt}) + end +end + -- add command: compile source files -- -- @param sourcefiles the source file paths diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua index c2840a591..3b4fe8296 100644 --- a/xmake/modules/private/utils/toolchain.lua +++ b/xmake/modules/private/utils/toolchain.lua @@ -343,6 +343,25 @@ function map_linkflags_for_package(package, targetkind, sourcekinds, name, value return flags end +-- ask the clang driver for the absolute path of the given library +-- +-- clang knows its own library search paths, e.g. the per-target runtime directory +-- (`lib/<target-triple>/libc++.a`), and it also works when the toolchain has no `--sdk=/xxx/llvm`. +-- +-- it just echoes back the given filename if the library does not exist, +-- so we only accept an existing absolute path. +function _get_llvm_libfile(toolchain, clang, libname, opt) + local argv = table.wrap(get_clang_target_flags(toolchain)) + table.insert(argv, "-print-file-name=" .. libname) + local libfile = try {function () return os.iorunv(clang, argv, {envs = opt.envs}) end} + if libfile then + libfile = path.normalize(libfile:trim()) + if path.is_absolute(libfile) and os.isfile(libfile) then + return libfile + end + end +end + -- Check and cache llvm/clang driver info (e.g. -print-resource-dir/-print-target-triple) in toolchain:config(). -- It must be collected during toolchain on_check so that toolchain on_load can use it without running clang again. -- @see https://github.com/xmake-io/xmake/issues/7337#issuecomment-3942499208 @@ -370,6 +389,17 @@ function check_llvm_info(toolchain, clang, opt) toolchain:config_set("llvm_target_triple", target_triple) end end + + -- the static c++ runtime archives, they may be in the per-target runtime directory, + -- e.g. `lib/x86_64-unknown-linux-gnu/libc++.a` + -- @see https://github.com/xmake-io/xmake/issues/7442 + for libname, configname in pairs({["libc++.a"] = "llvm_libcxx_static", ["libc++abi.a"] = "llvm_libcxxabi_static"}) do + local libfile = _get_llvm_libfile(toolchain, clang, libname, opt) + if libfile then + dprint("checking for llvm %s ... %s", libname, libfile) + toolchain:config_set(configname, libfile) + end + end end -- get llvm sdk resource directory @@ -457,6 +487,11 @@ function get_llvm_dirs(toolchain) end local bindir, libdir, cxxlibdir, includedir, cxxincludedir, resourcedir, rtdir, rtlink, rtlibdir + + -- the clang driver has already resolved the static c++ runtime archives on check + -- @see check_llvm_info + local libcxx_static = toolchain:config("llvm_libcxx_static") + local libcxxabi_static = toolchain:config("llvm_libcxxabi_static") if rootdir then bindir = path.join(rootdir, "bin") bindir = os.isdir(bindir) and bindir or nil @@ -476,6 +511,19 @@ function get_llvm_dirs(toolchain) end end + -- fallback to search the static c++ runtime archives in the library directories + if libdir and not (libcxx_static and libcxxabi_static) then + local staticdirs = cxxlibdir and {cxxlibdir, libdir} or {libdir} + for _, dir in ipairs(staticdirs) do + if not libcxx_static and os.isfile(path.join(dir, "libc++.a")) then + libcxx_static = path.join(dir, "libc++.a") + end + if not libcxxabi_static and os.isfile(path.join(dir, "libc++abi.a")) then + libcxxabi_static = path.join(dir, "libc++abi.a") + end + end + end + includedir = path.join(rootdir, "include") includedir = os.isdir(includedir) and includedir or nil @@ -502,7 +550,9 @@ function get_llvm_dirs(toolchain) resourcedir = resourcedir, rtdir = rtdir, rtlibdir = rtlibdir, - rtlink = rtlink } + rtlink = rtlink, + libcxx_static = libcxx_static, + libcxxabi_static = libcxxabi_static } memcache:set(cachekey, llvm_dirs) end return llvm_dirs @@ -645,7 +695,7 @@ function get_zig_target(toolchain) end if toolchain:is_plat("cross") then - -- xmake f -p cross --toolchain=zig --cross=mips64el-linux-gnuabi64 + -- xmake f -p cross --toolchain=zigcc --cross=mips64el-linux-gnuabi64 elseif toolchain:is_plat("macosx") then --@see https://github.com/ziglang/zig/issues/14226 target = arch .. "-macos-none" diff --git a/xmake/modules/private/xrepo/action/install.lua b/xmake/modules/private/xrepo/action/install.lua index b0d297b38..4abb57c7f 100644 --- a/xmake/modules/private/xrepo/action/install.lua +++ b/xmake/modules/private/xrepo/action/install.lua @@ -47,6 +47,9 @@ function menu_options() "e.g.", " - xrepo install -p cross --toolchain=mytool --includes='toolchain1.lua" .. path.envsep() .. "toolchain2.lua'"}, {nil, "policies", "kv", nil, "Set the policies." }, + {nil, "addon", "k", nil, "Install addon packages from <repository>/addons/"}, + {nil, "plugin", "k", nil, "Install plugin packages from <repository>/plugins/", + "(deprecated, please use --addon instead)"}, {category = "Visual Studio SDK Configuration" }, {nil, "vs", "kv", nil, "The Microsoft Visual Studio" , " e.g. --vs=2017" }, @@ -281,6 +284,12 @@ function _install_packages(packages) if option.get("build") or is_debug then table.insert(require_argv, "--build") end + if option.get("addon") then + table.insert(require_argv, "--addon") + end + if option.get("plugin") then + table.insert(require_argv, "--plugin") + end local extra = {system = false} if mode == "debug" then extra.debug = true diff --git a/xmake/modules/private/xrepo/action/remove.lua b/xmake/modules/private/xrepo/action/remove.lua index ed92a83b8..eed956c6e 100644 --- a/xmake/modules/private/xrepo/action/remove.lua +++ b/xmake/modules/private/xrepo/action/remove.lua @@ -20,6 +20,7 @@ -- imports import("core.base.option") +import("core.package.addon") import("private.action.require.impl.remove_packages", {alias = "remove_all_packages"}) -- get menu options @@ -44,6 +45,10 @@ function menu_options() {nil, "toolchain", "kv", nil, "Set the toolchain name." }, {nil, "toolchain_host", "kv", nil, "Set the host toolchain name." }, { }, + {nil, "addon", "k", nil, "Remove the given installed addon packages.", + "e.g.", + " - xrepo remove --addon serial-monitor" }, + {'f', "force", "k", nil, "Force to remove the addon packages, even if they are depended on by the others." }, {nil, "all", "k", nil, "Remove all packages and ignore extra package configs.", "If `--all` is enabled, the package name parameter will support lua pattern", "e.g.", @@ -193,10 +198,21 @@ function _remove_packages(packages) os.vexecv(os.programfile(), require_argv) end +-- remove the given installed addons +function _remove_addons(names) + for _, name in ipairs(names) do + addon.remove(name, {force = option.get("force")}) + cprint("${color.success}remove ${bright}%s${clear} ok!", name) + end +end + -- main entry function main() local packages = option.get("packages") - if option.get("all") then + if option.get("addon") then + assert(packages, "please specify the addons to be removed.") + _remove_addons(packages) + elseif option.get("all") then remove_all_packages(packages) elseif packages then _remove_packages(packages) diff --git a/xmake/modules/private/xrepo/action/search.lua b/xmake/modules/private/xrepo/action/search.lua index d389e3833..c532af44e 100644 --- a/xmake/modules/private/xrepo/action/search.lua +++ b/xmake/modules/private/xrepo/action/search.lua @@ -30,6 +30,9 @@ function menu_options() -- menu options local options = { + {nil, "addon", "k", nil, "Search the addon packages from <repository>/addons/", + "e.g.", + " - xrepo search --addon serial"}, {nil, "packages", "vs", nil, "The packages list (support lua pattern).", "e.g.", " - xrepo search zlib boost", @@ -80,6 +83,9 @@ function _search_packages(packages) if option.get("diagnosis") then table.insert(require_argv, "-D") end + if option.get("addon") then + table.insert(require_argv, "--addon") + end table.join2(require_argv, packages) os.vexecv(os.programfile(), require_argv) end diff --git a/xmake/modules/private/xrepo/quick_search/cache.lua b/xmake/modules/private/xrepo/quick_search/cache.lua index cf75a212d..feba8cda9 100644 --- a/xmake/modules/private/xrepo/quick_search/cache.lua +++ b/xmake/modules/private/xrepo/quick_search/cache.lua @@ -25,20 +25,36 @@ import("private.action.require.impl.repository") local cache = globalcache.cache("quick_search") +-- get the cache key of the given package +-- +-- @note the addons are stored with the `addon::` prefix, +-- because an addon and a package may have the same name +-- +function _cachekey(packagename, kind) + return kind == "addon" and ("addon::" .. packagename) or packagename +end + -- search package directories from repositories +-- +-- the packages are stored in <repodir>/packages/<first-letter>/<name>, +-- and the addons are stored in <repodir>/addons/<first-letter>/<name> +-- function _list_package_dirs() -- find the package directories from all repositories local unique = {} local packageinfos = {} for _, repo in ipairs(repository.repositories()) do - for _, file in ipairs(os.files(path.join(repo:directory(), "packages", "*", "*", "xmake.lua"))) do - local dir = path.directory(file) - local subdirname = path.basename(path.directory(dir)) - if #subdirname == 1 then -- ignore l/luajit/port/xmake.lua - local packagename = path.filename(dir) - if not unique[packagename] then - table.insert(packageinfos, {name = packagename, repo = repo, packagedir = dir}) - unique[packagename] = true + for _, rootinfo in ipairs({{rootdir = "packages"}, {rootdir = "addons", kind = "addon"}}) do + for _, file in ipairs(os.files(path.join(repo:directory(), rootinfo.rootdir, "*", "*", "xmake.lua"))) do + local dir = path.directory(file) + local subdirname = path.basename(path.directory(dir)) + if #subdirname == 1 then -- ignore l/luajit/port/xmake.lua + local packagename = path.filename(dir) + local cachekey = _cachekey(packagename, rootinfo.kind) + if not unique[cachekey] then + table.insert(packageinfos, {name = packagename, kind = rootinfo.kind, repo = repo, packagedir = dir}) + unique[cachekey] = true + end end end end @@ -57,7 +73,9 @@ end function update() for _, packageinfo in ipairs(_list_package_dirs()) do local package = core_package.load_from_repository(packageinfo.name, packageinfo.packagedir, {repo = packageinfo.repo}) - cache:set(packageinfo.name, { + cache:set(_cachekey(packageinfo.name, packageinfo.kind), { + name = packageinfo.name, + kind = packageinfo.kind, reponame = package:repo() and package:repo():name(), description = package:description(), versions = package:versions(), @@ -79,22 +97,30 @@ function get() end -- find package +-- +-- @param name the package name (support lua pattern) +-- @param opt the options, e.g. {prefix = true, description = true, kind = "addon"} +-- function find(name, opt) _init() opt = opt or {} local list_result = {} - for packagename, packagedata in pairs(cache:data()) do - local found = false - if opt.prefix then - found = packagename:startswith(name) - else - found = packagename:find(path.pattern(name)) - end - if not found and opt.description and packagedata.description and packagedata.description:find(name) then - found = true - end - if found then - table.insert(list_result, {name = packagename, data = packagedata}) + for cachekey, packagedata in table.orderpairs(cache:data()) do + -- we only search the packages with the given kind, e.g. nil (package), "addon" + local packagename = packagedata.name or cachekey + if packagedata.kind == opt.kind then + local found = false + if opt.prefix then + found = packagename:startswith(name) + else + found = packagename:find(path.pattern(name)) + end + if not found and opt.description and packagedata.description and packagedata.description:find(name) then + found = true + end + if found then + table.insert(list_result, {name = packagename, data = packagedata}) + end end end return list_result diff --git a/xmake/platforms/bsd/xmake.lua b/xmake/platforms/bsd/xmake.lua index 98143d019..89ab580fe 100644 --- a/xmake/platforms/bsd/xmake.lua +++ b/xmake/platforms/bsd/xmake.lua @@ -21,7 +21,7 @@ platform("bsd") set_os("bsd") set_hosts("bsd") - set_archs("i386", "x86_64") + set_archs("i386", "x86_64", "arm", "arm64", "ppc", "ppc64", "ppc64el", "riscv64", "sparc64") set_formats("static", "lib$(name).a") set_formats("object", "$(name).o") @@ -53,5 +53,3 @@ platform("bsd") , {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" } } } - - diff --git a/xmake/platforms/cross/xmake.lua b/xmake/platforms/cross/xmake.lua index 98bb31634..462fc961b 100644 --- a/xmake/platforms/cross/xmake.lua +++ b/xmake/platforms/cross/xmake.lua @@ -20,7 +20,7 @@ platform("cross") set_hosts("macosx", "linux", "windows", "bsd") - set_archs("i386", "x86_64", "arm", "arm64", "mips", "mips64", "riscv", "riscv64", "loong64", "s390x", "ppc", "ppc64", "sh4") + set_archs("i386", "x86_64", "arm", "armv7", "arm64", "mips", "mips64", "mips64el", "riscv", "riscv64", "loong64", "s390x", "ppc", "ppc64", "ppc64el", "sh4", "sparc64") set_formats("static", "lib$(name).a") set_formats("object", "$(name).o") @@ -28,5 +28,3 @@ platform("cross") set_formats("symbol", "$(name).sym") set_toolchains("envs", "cross") - - diff --git a/xmake/platforms/linux/xmake.lua b/xmake/platforms/linux/xmake.lua index c4d09880e..c26f99fb5 100644 --- a/xmake/platforms/linux/xmake.lua +++ b/xmake/platforms/linux/xmake.lua @@ -21,7 +21,7 @@ platform("linux") set_os("linux") set_hosts("macosx", "linux", "windows", "bsd") - set_archs("i386", "x86_64", "armv7", "armv7s", "arm64", "mips", "mips64", "mipsel", "mips64el", "loong64") + set_archs("i386", "x86_64", "armv7", "armv7s", "arm64", "mips", "mips64", "mipsel", "mips64el", "loong64", "riscv64", "s390x", "ppc", "ppc64", "ppc64el", "sparc64") set_formats("static", "lib$(name).a") set_formats("object", "$(name).o") diff --git a/xmake/platforms/solaris/xmake.lua b/xmake/platforms/solaris/xmake.lua index 5abdde4fb..260bc138b 100644 --- a/xmake/platforms/solaris/xmake.lua +++ b/xmake/platforms/solaris/xmake.lua @@ -21,7 +21,7 @@ platform("solaris") set_os("solaris") set_hosts("solaris") - set_archs("i386", "x86_64") + set_archs("i386", "x86_64", "sparc64") set_formats("static", "lib$(name).a") set_formats("object", "$(name).o") @@ -53,5 +53,3 @@ platform("solaris") , {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" } } } - - diff --git a/xmake/plugins/doxygen/main.lua b/xmake/plugins/doxygen/main.lua index 80fd77675..b84754cb2 100644 --- a/xmake/plugins/doxygen/main.lua +++ b/xmake/plugins/doxygen/main.lua @@ -71,6 +71,10 @@ end function main() + -- @note we cannot use utils.warning() here, it's queued and only shown at the end + cprint("${bright color.warning}${text.warning}: ${color.warning}the builtin `xmake doxygen` plugin is deprecated, " .. + "please use the doxygen-plugin addon: `xmake addon --install doxygen-plugin`") + -- load configuration config.load() diff --git a/xmake/plugins/format/main.lua b/xmake/plugins/format/main.lua index 408de0421..c8f50a15e 100644 --- a/xmake/plugins/format/main.lua +++ b/xmake/plugins/format/main.lua @@ -103,6 +103,10 @@ end -- main function main() + -- @note we cannot use utils.warning() here, it's queued and only shown at the end + cprint("${bright color.warning}${text.warning}: ${color.warning}the builtin `xmake format` plugin is deprecated, " .. + "please use the format-plugin addon: `xmake addon --install format-plugin`") + -- load configuration config.load() diff --git a/xmake/plugins/macro/main.lua b/xmake/plugins/macro/main.lua index 86b50e2da..6c2c8c734 100644 --- a/xmake/plugins/macro/main.lua +++ b/xmake/plugins/macro/main.lua @@ -309,6 +309,10 @@ end -- main function main() + -- @note we cannot use utils.warning() here, it's queued and only shown at the end + cprint("${bright color.warning}${text.warning}: ${color.warning}the builtin `xmake macro` plugin is deprecated, " .. + "please use the macro-plugin addon: `xmake addon --install macro-plugin`") + -- list macros if option.get("list") then diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index e12461883..f91c15273 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -326,7 +326,7 @@ function _pack_wix(wix, package) table.join2(argv, {"-ext", "WixToolset.UI.wixext"}) table.join2(argv, {"-o", package:outputfile()}) - if package:arch() == "x64" then + if package:is_arch("x64", "x86_64") then table.join2(argv, {"-arch", "x64"}) elseif package:arch() == "x86" then table.join2(argv, {"-arch", "x86"}) diff --git a/xmake/plugins/plugin/main.lua b/xmake/plugins/plugin/main.lua index b362381e4..ce1ac3e4f 100644 --- a/xmake/plugins/plugin/main.lua +++ b/xmake/plugins/plugin/main.lua @@ -21,146 +21,235 @@ -- imports import("core.base.option") import("core.base.global") +import("core.package.repository") import("devel.git") -import("net.fasturl") import("private.action.require.impl.environment") +import("private.action.require.impl.install_packages") --- get plugin urls -function _plugin_urls() - local urls = option.get("plugins") - if urls then - local result = {} - for _, url in ipairs(urls) do - table.insert(result, git.asgiturl(url) or url) - end - urls = result - else - urls = { - "https://github.com/xmake-io/xmake-plugins.git", - "https://gitlab.com/tboox/xmake-plugins.git", - "https://gitee.com/tboox/xmake-plugins.git"} - urls = fasturl.add(urls) - urls = fasturl.sort(urls) +-- validate a plugin directory name +function _check_plugin_name(name) + assert(type(name) == "string" and name ~= "" and name ~= "." and not name:find("..", 1, true) and not name:find("[/\\:]"), "invalid plugin name(%s)!", name) + return name +end + +-- get plugin directory in ~/.xmake/plugins +function _get_plugindir(name) + local plugindir = path.join(global.directory(), "plugins") + return name and path.join(plugindir, _check_plugin_name(name)) or plugindir +end + +-- get local and global repositories, with local taking precedence +function _repositories() + return table.join(repository.repositories({global = false}), repository.repositories({global = true})) +end + +-- install a plugin from the given repository or the first repository containing it +function _install_plugins_from_repo(name, reponame) + + -- check plugin name + _check_plugin_name(name) + + -- do install + local installname = name + if reponame then + installname = reponame .. "@" .. name + end + local argv = {"lua", "private.xrepo", "install", "--plugin"} + -- we need to pass the common options to the sub-process, e.g. -y, -v, -D + if option.get("yes") then + table.insert(argv, "-y") end - return urls + if option.get("verbose") then + table.insert(argv, "-v") + end + if option.get("diagnosis") then + table.insert(argv, "-D") + end + table.insert(argv, installname) + os.execv(os.programfile(), argv) end --- get manifest path -function _manifest_path() - return path.join(global.directory(), "plugins", "manifest.txt") +-- install a single plugin from a source directory (as the given name, default to the directory name) +function _install_from_local(dir, name) + assert(os.isdir(dir) and os.isfile(path.join(dir, "xmake.lua")), "plugin path(%s): ${bright}xmake.lua${clear} not found!", dir) + name = name or path.filename(path.absolute(dir)) + local dstdir = _get_plugindir(name) + assert(not os.isdir(dstdir), "plugin(%s) already exists!", name) + os.vcp(dir, dstdir) + cprint("${color.success}install ${bright}%s${clear} ok!", name) end --- load manifest -function _load_manifest() - local manifest_path = _manifest_path() - if os.isfile(manifest_path) then - return io.load(manifest_path) +-- install a single plugin from a git url or github shortcut, e.g. https://github.com/xmake-io/hello-world +function _install_from_git(url) + local branch + if url:startswith("github:") then + local i = url:find("#", 1, true) + if i then + branch = url:sub(i + 1) + url = url:sub(1, i - 1) + end + url = git.asgiturl(url) end + local name = (path.filename(url):gsub("%.git$", "")) + local tmpdir = os.tmpfile() .. ".dir" + git.clone(url, {verbose = option.get("verbose"), branch = branch, outputdir = tmpdir}) + os.tryrm(path.join(tmpdir, ".git")) + _install_from_local(tmpdir, name) + os.tryrm(tmpdir) end --- save manifest -function _save_manifest(manifest) - io.save(_manifest_path(), manifest) +-- install a single plugin +function _install_one(name) + -- parse repo@plugin format + local i = name:find("@", 1, true) + if i and not name:find("[/\\:]") then + local reponame = name:sub(1, i - 1) + local pluginname = name:sub(i + 1) + _install_plugins_from_repo(pluginname, reponame) + return + end + + -- github shortcut: github:user/repo or github:user/repo#branch + if name:startswith("github:") then + _install_from_git(name) + return + end + + -- git url or local path + if git.asgiturl(name) then + _install_from_git(name) + return + elseif os.isdir(name) then + _install_from_local(name) + return + end + + -- plain name: try to find it in repositories + _install_plugins_from_repo(name) end -- install plugins function _install() - - -- enter environment + local names = assert(option.get("plugins"), "please specify the plugins to be installed!") environment.enter() + for _, name in ipairs(names) do + _install_one(name) + end + environment.leave() +end - try - { - function () +-- remove the given installed plugin +function _remove() + local names = assert(option.get("plugins"), "please specify the plugin name to be removed!") + assert(#names == 1, "please specify only one plugin name to be removed!") + local name = names[1] + local dir = _get_plugindir(name) + assert(os.isdir(dir), "plugin(%s) not found!", name) + os.rmdir(dir) + cprint("${color.success}remove ${bright}%s${clear} ok!", name) +end - -- do install - local urls = _plugin_urls() - local tmpdir = os.tmpfile() .. ".dir" - local plugindir = path.join(global.directory(), "plugins") - local installed_url - for _, url in ipairs(urls) do - cprint("installing plugins from %s ..", url) - git.clone(url, {verbose = option.get("verbose"), outputdir = tmpdir}) - installed_url = url - break - end - for _, filepath in ipairs(os.files(path.join(tmpdir, "*", "xmake.lua"))) do - local srcdir = path.directory(filepath) - local name = path.filename(srcdir) - local dstdir = path.join(plugindir, name) - assert(not os.isdir(dstdir), "plugin(%s) already exists!", name) - os.vcp(srcdir, dstdir) - cprint(" ${yellow}->${clear} %s", name) - end - os.tryrm(tmpdir) +-- get the description of a plugin from its xmake.lua menu +function _plugin_description(dir) + local filepath = path.join(dir, "xmake.lua") + if os.isfile(filepath) then + local content = io.readfile(filepath) + if content then + -- parse description from task or package scope + return content:match("description%s*=%s*\"(.-)\"") or content:match("set_description%s*%(\"(.-)\"%)") + end + end +end - -- save manifest - if installed_url then - local manifest = _load_manifest() or {} - manifest.urls = manifest.urls or {} - table.join2(manifest.urls, installed_url) - _save_manifest(manifest) - end - cprint("${bright}all plugins have been installed in %s!", plugindir) - end, - catch - { - function (errors) - raise(errors) +-- collect plugins (each subdirectory containing xmake.lua) under the given root +-- +-- built-in/installed plugins are flat (<root>/<name>), while plugins in a +-- repository follow the packages layout (<root>/<first-letter>/<name>) +function _collect_plugins(root, seen, nested) + local entries = {} + local pattern = nested and path.join(root, "*", "*") or path.join(root, "*") + for _, dir in ipairs(os.dirs(pattern) or {}) do + local name = path.filename(dir) + if os.isfile(path.join(dir, "xmake.lua")) and (not seen or not seen[name]) then + if seen then + seen[name] = true end - } - } + table.insert(entries, {name = name, description = _plugin_description(dir)}) + end + end + return entries +end - -- leave environment - environment.leave() +-- print a plugin entry with its description aligned on the right +function _print_plugin(name, description, width, note) + local suffix = description or "" + if note then + suffix = suffix ~= "" and (suffix .. " " .. note) or note + end + if suffix ~= "" then + local padding = math.max(width - #name, 1) + cprint(" ${color.dump.string}%s${clear}%s%s", name, (" "):rep(padding), suffix) + else + cprint(" ${color.dump.string}%s${clear}", name) + end end --- update plugins -function _update() +-- list all plugins +function _list() + local seen = {} - -- enter environment - environment.enter() + -- collect plugins from every source + local builtin = _collect_plugins(path.join(os.programdir(), "plugins"), seen) + local plugindir = _get_plugindir() + local installed = _collect_plugins(plugindir, seen) + local avail = {} + for _, repo in ipairs(_repositories()) do + table.join2(avail, _collect_plugins(path.join(repo:directory(), "plugins"), seen, true)) + end - try - { - function () + -- compute the alignment width from all plugin names + local width = 0 + for _, entries in ipairs({builtin, installed, avail}) do + for _, entry in ipairs(entries) do + width = math.max(width, #entry.name + 4) + end + end - -- do update - local manifest = _load_manifest() - assert(manifest and manifest.urls, "3rd plugins not found!") - local urls = manifest.urls - local plugindir = path.join(global.directory(), "plugins") - for _, url in ipairs(urls) do - cprint("updating plugins from %s ..", url) - local tmpdir = os.tmpfile() .. ".dir" - git.clone(url, {verbose = option.get("verbose"), outputdir = tmpdir}) - for _, filepath in ipairs(os.files(path.join(tmpdir, "*", "xmake.lua"))) do - local srcdir = path.directory(filepath) - local name = path.filename(srcdir) - local dstdir = path.join(plugindir, name) - os.tryrm(dstdir) - os.vcp(srcdir, dstdir) - cprint(" ${yellow}->${clear} %s", name) - end - os.tryrm(tmpdir) - end - cprint("${bright}all plugins have been updated in %s!", plugindir) - end, - catch - { - function (errors) - raise(errors) - end - } - } + -- built-in plugins + cprint("${bright}the built-in plugins:${clear}") + if #builtin > 0 then + for _, entry in ipairs(builtin) do + _print_plugin(entry.name, entry.description, width) + end + else + print(" (none)") + end - -- leave environment - environment.leave() + -- installed plugins + cprint("${bright}the installed plugins:${clear}") + if #installed > 0 then + for _, entry in ipairs(installed) do + _print_plugin(entry.name, entry.description, width) + end + else + print(" (none)") + end + + -- plugins available in repositories (not yet installed) + cprint("${bright}available in configured repositories:${clear}") + if #avail > 0 then + for _, entry in ipairs(avail) do + local note = string.format("(run xmake plugin --install %s to install)", entry.name) + _print_plugin(entry.name, entry.description, width, note) + end + else + print(" (none)") + end end -- clear all installed plugins function _clear() - local plugindir = path.join(global.directory(), "plugins") + local plugindir = _get_plugindir() if os.isdir(plugindir) then os.rmdir(plugindir) end @@ -168,12 +257,14 @@ function _clear() end function main() + cprint("${bright color.warning}${text.warning}: ${color.warning}`xmake plugin` is deprecated, please use `xmake addon` instead!") if option.get("install") then _install() - elseif option.get("update") then - _update() + elseif option.get("remove") then + _remove() + elseif option.get("list") then + _list() elseif option.get("clear") then _clear() end end - diff --git a/xmake/plugins/plugin/xmake.lua b/xmake/plugins/plugin/xmake.lua index 05d9e3631..1136b0044 100644 --- a/xmake/plugins/plugin/xmake.lua +++ b/xmake/plugins/plugin/xmake.lua @@ -23,14 +23,21 @@ task("plugin") on_run("main") set_menu { usage = "xmake plugin [options]", - description = "Manage plugins of xmake.", + description = "Manage plugins of xmake. (deprecated, please use `xmake addon` instead)", options = { {'i', "install", "k", nil, "Install plugins."}, - {'u', "update", "k", nil, "Update plugins."}, + {'r', "remove", "k", nil, "Remove the given installed plugin."}, + {'l', "list", "k", nil, "List all installed plugins."}, {'c', "clear", "k", nil, "Clear all installed plugins."}, - {nil, "plugins", "v", nil, "The plugins path or url.", + {nil, "plugins", "vs", nil, "The plugin paths, urls or names.", "e.g.", - " $ xmake plugin --install https://github.com/xmake-io/xmake-plugins", - " $ xmake plugin --update"} + " $ xmake plugin --install https://github.com/myrepo/hello-world", + " $ xmake plugin --install github:myrepo/hello-world", + " $ xmake plugin --install github:myrepo/hello-world#dev", + " $ xmake plugin --install /tmp/my-plugin", + " $ xmake plugin --install xmake-repo@hello-world", + " $ xmake plugin --install hello-world", + " $ xmake plugin --remove hello-world", + " $ xmake plugin --list"} } } diff --git a/xmake/plugins/project/clang/compile_commands.lua b/xmake/plugins/project/clang/compile_commands.lua index 2f25194cc..a8fdb547f 100644 --- a/xmake/plugins/project/clang/compile_commands.lua +++ b/xmake/plugins/project/clang/compile_commands.lua @@ -69,10 +69,13 @@ end -- specify windows sdk verison function _get_windows_sdk_arguments(target) local args = {} - local msvc = target:toolchain("msvc") - if msvc then - local envs = msvc:runenvs() - if envs then + if target and target:is_plat("windows") then + local toolchain = target:toolchain("msvc") or + target:toolchain("clang-cl") or + target:toolchain("clang") or + target:toolchain("llvm") + local envs = toolchain and toolchain:runenvs() + if envs and envs.INCLUDE then for _, dir in ipairs(path.splitenv(envs.INCLUDE)) do table.insert(args, "-imsvc") table.insert(args, dir) diff --git a/xmake/plugins/project/ninja/build_ninja.lua b/xmake/plugins/project/ninja/build_ninja.lua index f89915e02..bd9a3d292 100644 --- a/xmake/plugins/project/ninja/build_ninja.lua +++ b/xmake/plugins/project/ninja/build_ninja.lua @@ -37,7 +37,8 @@ function _sourcebatch_is_built(sourcebatch) local rulename = sourcebatch.rulename if rulename == "c.build" or rulename == "c++.build" or rulename == "asm.build" or rulename == "cuda.build" - or rulename == "objc.build" or rulename == "objc++.build" then + or rulename == "objc.build" or rulename == "objc++.build" + or rulename == "win.sdk.resource" then return true end end diff --git a/xmake/plugins/project/utils/target_cmds.lua b/xmake/plugins/project/utils/target_cmds.lua index 7ea3a13a0..1c5fed7c8 100644 --- a/xmake/plugins/project/utils/target_cmds.lua +++ b/xmake/plugins/project/utils/target_cmds.lua @@ -87,6 +87,9 @@ function get_target_buildcmds(target, opt) cmd.program = os.programfile() cmd.argv = table.join("lua", cmd.script, cmd.argv) cmd.script = nil + elseif cmd.func and kind == "call" then + local name = cmd.opt and cmd.opt.name or "unknown" + wprint("%s: batchcmds:call() is not supported by the project generator and will be ignored!", name) end end return buildcmds:cmds() diff --git a/xmake/rules/c++/modules/builder.lua b/xmake/rules/c++/modules/builder.lua index 6d82cca0b..d0863ad98 100644 --- a/xmake/rules/c++/modules/builder.lua +++ b/xmake/rules/c++/modules/builder.lua @@ -85,6 +85,23 @@ function _get_buildfilejob_for(target, sourcefile, opt) return _get_module_buildfilejob_for(target, sourcefile, opt.moduletype) end +-- merge jobdeps, we cannot use table.join2 directly, +-- because it will override the previous deps with the same job name +-- +-- e.g. a consumer job may depend on several reused bmi jobs from the same dep target +-- @see https://github.com/xmake-io/xmake/issues/7690 +function _merge_jobdeps(jobdeps, deps) + for jobname, depnames in pairs(deps) do + local orderdeps = jobdeps[jobname] + if orderdeps then + table.join2(orderdeps, depnames) + else + jobdeps[jobname] = table.wrap(depnames) + end + end + return jobdeps +end + function _get_jobdeps(target, module, jobgraph, buildfilejob) local memcache = support.memcache() @@ -236,11 +253,11 @@ function build_modules_for_jobgraph(target, jobgraph, built_modules) else if not support.is_bmionly(target, sourcefile) then local buildfilejob = _get_module_buildfilejob_for(target, sourcefile, "objectfile") - table.join2(jobdeps, _get_jobdeps(target, module, jobgraph, buildfilejob)) + _merge_jobdeps(jobdeps, _get_jobdeps(target, module, jobgraph, buildfilejob)) table.insert(buildfilejobs, buildfilejob) local objbuildfilejob = target:fullname() .. "/obj/" .. sourcefile if jobgraph:has(objbuildfilejob) then - jobdeps[objbuildfilejob] = {buildfilejob} + _merge_jobdeps(jobdeps, {[objbuildfilejob] = {buildfilejob}}) end end end @@ -262,19 +279,19 @@ function build_modules_for_jobgraph(target, jobgraph, built_modules) jobopt.objectfile = not has_two_phase_compilation_support and not bmionly builder.make_module_job(target, module, jobopt) end) - table.join2(jobdeps, _get_jobdeps(target, module, jobgraph, buildfilejob)) + _merge_jobdeps(jobdeps, _get_jobdeps(target, module, jobgraph, buildfilejob)) -- if two phase compilation supported set jobdeps for objectfile job if has_two_phase_compilation_support and not bmionly then local objbuildfilejob = _get_module_buildfilejob_for(target, sourcefile, "objectfile") - jobdeps[objbuildfilejob] = {buildfilejob} + _merge_jobdeps(jobdeps, {[objbuildfilejob] = {buildfilejob}}) end end end) -- insert saved jobdeps for _, buildfilejob in ipairs(buildfilejobs) do - table.join2(jobdeps, _get_saved_jobdeps_for(jobgraph, buildfilejob)) + _merge_jobdeps(jobdeps, _get_saved_jobdeps_for(jobgraph, buildfilejob)) end -- apply jobdeps diff --git a/xmake/rules/c++/modules/clang/scanner.lua b/xmake/rules/c++/modules/clang/scanner.lua index d73c40621..f0023cb7c 100644 --- a/xmake/rules/c++/modules/clang/scanner.lua +++ b/xmake/rules/c++/modules/clang/scanner.lua @@ -59,7 +59,8 @@ function scan_dependency_for(target, sourcefile, rescan, opt) if option.get("verbose") then print(os.args(table.join(clangscandeps, dependency_flags))) end - local outdata, errdata = os.iorunv(clangscandeps, dependency_flags) + local outdata, errdata = os.iorunv(clangscandeps, dependency_flags, + {envs = compinst:runenvs()}) assert(outdata, errdata) io.writefile(jsonfile, outdata) @@ -77,7 +78,7 @@ function scan_dependency_for(target, sourcefile, rescan, opt) end) local ifile = path.translate(path.join(outputdir, path.filename(file) .. ".i")) compflags = table.join(compflags or {}, keepsystemincludesflag or {}, {"-E", "-x", "c++", file, "-o", ifile}) - os.vrunv(compinst:program(), compflags) + os.vrunv(compinst:program(), compflags, {envs = compinst:runenvs()}) local content = io.readfile(ifile) os.rm(ifile) return content diff --git a/xmake/rules/c++/modules/clang/support.lua b/xmake/rules/c++/modules/clang/support.lua index b1699d21a..71bd2e735 100644 --- a/xmake/rules/c++/modules/clang/support.lua +++ b/xmake/rules/c++/modules/clang/support.lua @@ -46,7 +46,10 @@ function _get_toolchain_includedirs_for_stlheaders(target, includedirs, clang) table.insert(argv, 1, "-stdlib=libstdc++") end end - local result = try {function () return os.iorunv(clang, argv, {envs = compinst:runenvs()}) end} + local compinst = target:compiler("cxx") + local result = try {function () + return os.iorunv(clang, argv, {envs = compinst and compinst:runenvs()}) + end} if result then for _, line in ipairs(result:split("\n", {plain = true})) do local line = line:trim() @@ -64,17 +67,25 @@ end function _get_std_module_manifest_path(target) local print_module_manifest_flag = get_print_library_module_manifest_path_flag(target) - local clang_path = path.directory(get_clang_path(target)) + local clang_path = get_clang_path(target) + if not clang_path then + return + end + local clang_dir = path.directory(clang_path) if print_module_manifest_flag then local compinst = target:compiler("cxx") - local outdata, _ = try { function() return os.iorunv(compinst:program(), {"-std=c++23", "-stdlib=libc++", "--sysroot=" .. path.join(clang_path, ".."), print_module_manifest_flag}, {envs = compinst:runenvs()}) end } + local sysroot = "--sysroot=" .. path.join(clang_dir, "..") + local flags = {"-std=c++23", "-stdlib=libc++", sysroot, print_module_manifest_flag} + local outdata, _ = try {function() + return os.iorunv(compinst:program(), flags, {envs = compinst:runenvs()}) + end} if outdata and not outdata:startswith("<NOT PRESENT>") then return outdata:trim() end end -- fallback on custom detection -- manifest can be found in <llvm_path>/lib subdirectory (i.e on debian it should be <llvm_path>/lib/x86_64-unknown-linux-gnu/) - local clang_lib_path = path.join(clang_path, "..", "lib") + local clang_lib_path = path.join(clang_dir, "..", "lib") local modules_json_path = path.join(clang_lib_path, "libc++.modules.json") if not os.isfile(modules_json_path) then modules_json_path = find_file("*/libc++.modules.json", clang_lib_path) @@ -161,7 +172,11 @@ function toolchain_includedirs(target) runtime_flag = "-stdlib=libstdc++" end end - local _, result = try {function () return os.iorunv(clang, table.join({"-E", "-Wp,-v", "-xc++", os.nuldev()}, runtime_flag or {})) end} + local compinst = target:compiler("cxx") + local flags = table.join({"-E", "-Wp,-v", "-xc++", os.nuldev()}, runtime_flag or {}) + local _, result = try {function () + return os.iorunv(clang, flags, {envs = compinst and compinst:runenvs()}) + end} if result then for _, line in ipairs(result:split("\n", {plain = true})) do local line = line:trim() @@ -183,8 +198,10 @@ function get_clang_path(target) if not clang_path then local program, toolname = target:tool("cxx") if program and toolname:startswith("clang") then + local compinst = target:compiler("cxx") + local envs = compinst and compinst:runenvs() or os.getenvs() local clang = find_tool(toolname, {program = program, - envs = os.getenvs(), cachekey = "modules_support_clang_" .. toolname}) + envs = envs, cachekey = "modules_support_clang_" .. toolname}) if clang then clang_path = clang.program end @@ -201,8 +218,10 @@ function get_clang_version(target) if not clang_version then local program, toolname = target:tool("cxx") if program and toolname:startswith("clang") then + local compinst = target:compiler("cxx") + local envs = compinst and compinst:runenvs() or os.getenvs() local clang = find_tool(toolname, {program = program, version = true, - envs = os.getenvs(), cachekey = "modules_support_clang_" .. toolname}) + envs = envs, cachekey = "modules_support_clang_" .. toolname}) if clang then clang_version = clang.version end @@ -229,10 +248,13 @@ function get_clang_scan_deps(target) if dir and dir ~= "." and os.isdir(dir) then program = path.join(dir, program) end - local result = find_tool("clang-scan-deps", {program = program, version = true}) + local compinst = target:compiler("cxx") + local envs = compinst and compinst:runenvs() or os.getenvs() + local result = find_tool("clang-scan-deps", + {program = program, version = true, envs = envs}) if not result then -- find a system wide alternative - result = find_tool("clang-scan-deps", {version = true}) + result = find_tool("clang-scan-deps", {version = true, envs = envs}) end if result then clang_scan_deps = result.program @@ -295,9 +317,16 @@ function get_stdmodules(target) return {path.normalize(path.join(try_std_module_directory, "std.cppm")), path.normalize(path.join(try_std_module_directory, "std.compat.cppm"))} end -- then try the directory relative to clang bin directory - try_std_module_directory = path.join(path.directory(get_original_file(get_clang_path(target))), std_module_directory) - if os.isdir(try_std_module_directory) then - return {path.normalize(path.join(try_std_module_directory, "std.cppm")), path.normalize(path.join(try_std_module_directory, "std.compat.cppm"))} + local clang_path = get_clang_path(target) + if clang_path then + local clang_dir = path.directory(get_original_file(clang_path)) + try_std_module_directory = path.join(clang_dir, std_module_directory) + if os.isdir(try_std_module_directory) then + return { + path.normalize(path.join(try_std_module_directory, "std.cppm")), + path.normalize(path.join(try_std_module_directory, "std.compat.cppm")) + } + end end elseif cpplib == "stdc++" then -- dont be greedy and don't enable stdc++ std module support for llvm < 19 diff --git a/xmake/rules/c++/modules/support.lua b/xmake/rules/c++/modules/support.lua index 126e25c61..38df28a05 100644 --- a/xmake/rules/c++/modules/support.lua +++ b/xmake/rules/c++/modules/support.lua @@ -92,7 +92,15 @@ function get_cpplibrary_name(target) end elseif target:is_plat("macosx", "iphoneos", "watchos", "appletvos", "applexros", "bsd", "harmony") then return "c++" - elseif target:is_plat("linux", "mingw", "cygwin", "msys", "haiku") then + elseif target:is_plat("linux", "cygwin", "msys", "haiku") then + return "stdc++" + elseif target:is_plat("mingw") then + local toolchain_inst = target:toolchain("mingw") + local is_clang = (toolchain_inst and toolchain_inst:config("clang")) or + target:has_tool("cxx", "clang", "clangxx", "clang_cl") + if is_clang then + return "c++" + end return "stdc++" elseif target:is_plat("windows") then return "msstl" diff --git a/xmake/rules/utils/bin2c/utils.lua b/xmake/rules/utils/bin2c/utils.lua index 405c2ed62..156752576 100644 --- a/xmake/rules/utils/bin2c/utils.lua +++ b/xmake/rules/utils/bin2c/utils.lua @@ -36,6 +36,7 @@ function generate_headerfile(target, batchcmds, binaryfile, opt) opt = opt or {} local rulename = opt.rulename or "utils.bin2c" local progress = opt.progress + local fileconfig = target:fileconfig(binaryfile) -- get header directory and file local headerdir = opt.headerdir @@ -52,6 +53,16 @@ function generate_headerfile(target, batchcmds, binaryfile, opt) -- add includedirs target:add("includedirs", headerdir) + -- transform binary data first + -- @see https://github.com/xmake-io/xmake/issues/7513 + local transform = opt.transform or (fileconfig and fileconfig.transform) or target:extraconf("rules", rulename, "transform") + if transform then + batchcmds:show_progress(progress, "${color.build.object}transforming.bin2c %s", binaryfile) + local transformed_file = target:autogenfile(binaryfile) + batchcmds:call(transform, {binaryfile, transformed_file}, {name = "bin2c/transform", target = target}) + binaryfile = transformed_file + end + -- add commands if progress then batchcmds:show_progress(progress, "${color.build.object}generating.bin2c %s", binaryfile) @@ -69,7 +80,6 @@ function generate_headerfile(target, batchcmds, binaryfile, opt) end -- get nozeroend/zeroend (check file-level config first, then rule-level config, then opt) - local fileconfig = target:fileconfig(binaryfile) local nozeroend = nil if fileconfig then if fileconfig.nozeroend ~= nil then diff --git a/xmake/rules/utils/bin2c/xmake.lua b/xmake/rules/utils/bin2c/xmake.lua index 9f6338758..0d2745b60 100644 --- a/xmake/rules/utils/bin2c/xmake.lua +++ b/xmake/rules/utils/bin2c/xmake.lua @@ -33,7 +33,7 @@ rule("utils.bin2c") -- generate header file local headerfile = bin2c_utils.generate_headerfile(target, batchcmds, sourcefile_bin, { - progress = opt.progress + progress = opt.progress, }) -- add deps diff --git a/xmake/rules/utils/bin2obj/utils.lua b/xmake/rules/utils/bin2obj/utils.lua index a14ba829a..dcd4b9c80 100644 --- a/xmake/rules/utils/bin2obj/utils.lua +++ b/xmake/rules/utils/bin2obj/utils.lua @@ -50,6 +50,7 @@ function generate_objectfile(target, batchcmds, binaryfile, opt) opt = opt or {} local rulename = opt.rulename or "utils.bin2obj" local progress = opt.progress + local fileconfig = target:fileconfig(binaryfile) -- check for cosmocc toolchain local is_cosmocc = target:toolchain("cosmocc") or (target:has_tool("cc", "cosmocc") and target:has_tool("ar", "cosmoar")) @@ -68,6 +69,16 @@ function generate_objectfile(target, batchcmds, binaryfile, opt) end end + -- transform binary data first + -- @see https://github.com/xmake-io/xmake/issues/7513 + local transform = opt.transform or (fileconfig and fileconfig.transform) or target:extraconf("rules", rulename, "transform") + if transform then + batchcmds:show_progress(progress, "${color.build.object}transforming.bin2obj %s", binaryfile) + local transformed_file = target:autogenfile(binaryfile) + batchcmds:call(transform, {binaryfile, transformed_file}, {name = "bin2obj/transform", target = target}) + binaryfile = transformed_file + end + -- get object file local objectfile = opt.objectfile if not objectfile then @@ -90,6 +101,9 @@ function generate_objectfile(target, batchcmds, binaryfile, opt) -- get zeroend (default: false, but can be overridden) local zeroend = opt.zeroend if zeroend == nil then + zeroend = fileconfig and fileconfig.zeroend + end + if zeroend == nil then zeroend = target:extraconf("rules", rulename, "zeroend") or false end diff --git a/xmake/rules/utils/bin2obj/xmake.lua b/xmake/rules/utils/bin2obj/xmake.lua index b826fbd99..f461e67ef 100644 --- a/xmake/rules/utils/bin2obj/xmake.lua +++ b/xmake/rules/utils/bin2obj/xmake.lua @@ -24,15 +24,9 @@ rule("utils.bin2obj") after_buildcmd_file(function (target, batchcmds, sourcefile_bin, opt) import("rules.utils.bin2obj.utils", {alias = "bin2obj_utils", rootdir = os.programdir()}) - -- get zeroend (default: false) - -- check file-level config first, then rule-level config - local fileconfig = target:fileconfig(sourcefile_bin) - local zeroend = (fileconfig and fileconfig.zeroend) or target:extraconf("rules", "utils.bin2obj", "zeroend") or false - -- convert binary file to object file local objectfile = bin2obj_utils.generate_objectfile(target, batchcmds, sourcefile_bin, { progress = opt.progress, - zeroend = zeroend }) -- add deps diff --git a/xmake/rules/utils/glsl2spv/xmake.lua b/xmake/rules/utils/glsl2spv/xmake.lua index 01abc561a..0374c2fe6 100644 --- a/xmake/rules/utils/glsl2spv/xmake.lua +++ b/xmake/rules/utils/glsl2spv/xmake.lua @@ -43,6 +43,7 @@ -- rule("utils.glsl2spv") set_extensions(".vert", ".tesc", ".tese", ".geom", ".comp", ".frag", ".comp", ".mesh", ".task", ".rgen", ".rint", ".rahit", ".rchit", ".rmiss", ".rcall", ".glsl") + add_orders("utils.glsl2spv", "c++.build.modules.scanner") on_load(function (target) local is_bin2c = target:extraconf("rules", "utils.glsl2spv", "bin2c") if is_bin2c then @@ -53,7 +54,7 @@ rule("utils.glsl2spv") target:add("includedirs", headerdir) end end) - before_buildcmd_file(function (target, batchcmds, sourcefile_glsl, opt) + on_preparecmd_file(function (target, batchcmds, sourcefile_glsl, opt) import("lib.detect.find_tool") import("rules.utils.bin2obj.utils", {alias = "bin2obj_utils", rootdir = os.programdir()}) import("rules.utils.bin2c.utils", {alias = "bin2c_utils", rootdir = os.programdir()}) diff --git a/xmake/rules/utils/hlsl2spv/xmake.lua b/xmake/rules/utils/hlsl2spv/xmake.lua index 750574eac..5eab8b25d 100644 --- a/xmake/rules/utils/hlsl2spv/xmake.lua +++ b/xmake/rules/utils/hlsl2spv/xmake.lua @@ -43,6 +43,7 @@ -- rule("utils.hlsl2spv") set_extensions(".hlsl") + add_orders("utils.hlsl2spv", "c++.build.modules.scanner") on_load(function (target) local is_bin2c = target:extraconf("rules", "utils.hlsl2spv", "bin2c") if is_bin2c then @@ -54,7 +55,7 @@ rule("utils.hlsl2spv") end end) - before_buildcmd_file(function (target, batchcmds, sourcefile_hlsl, opt) + on_preparecmd_file(function (target, batchcmds, sourcefile_hlsl, opt) import("lib.detect.find_tool") import("rules.utils.bin2obj.utils", {alias = "bin2obj_utils", rootdir = os.programdir()}) import("rules.utils.bin2c.utils", {alias = "bin2c_utils", rootdir = os.programdir()}) diff --git a/xmake/repository/templates/c++/console/src/main.cpp b/xmake/templates/c++/console/src/main.cpp index 9b6abffea..9b6abffea 100644 --- a/xmake/repository/templates/c++/console/src/main.cpp +++ b/xmake/templates/c++/console/src/main.cpp diff --git a/xmake/repository/templates/c++/console/xmake.lua b/xmake/templates/c++/console/xmake.lua index c73be8724..c73be8724 100644 --- a/xmake/repository/templates/c++/console/xmake.lua +++ b/xmake/templates/c++/console/xmake.lua diff --git a/xmake/repository/templates/c++/module/binary/.gitignore b/xmake/templates/c++/module/binary/.gitignore index 152105761..152105761 100644 --- a/xmake/repository/templates/c++/module/binary/.gitignore +++ b/xmake/templates/c++/module/binary/.gitignore diff --git a/xmake/repository/templates/c++/module/binary/modules/binary/bar/.gitignore b/xmake/templates/c++/module/binary/modules/binary/bar/.gitignore index 152105761..152105761 100644 --- a/xmake/repository/templates/c++/module/binary/modules/binary/bar/.gitignore +++ b/xmake/templates/c++/module/binary/modules/binary/bar/.gitignore diff --git a/xmake/repository/templates/c++/module/binary/modules/binary/bar/src/add.cpp b/xmake/templates/c++/module/binary/modules/binary/bar/src/add.cpp index 93fdf0ad8..93fdf0ad8 100644 --- a/xmake/repository/templates/c++/module/binary/modules/binary/bar/src/add.cpp +++ b/xmake/templates/c++/module/binary/modules/binary/bar/src/add.cpp diff --git a/xmake/repository/templates/c++/module/binary/modules/binary/bar/src/sub.cpp b/xmake/templates/c++/module/binary/modules/binary/bar/src/sub.cpp index ae7b6d1f2..ae7b6d1f2 100644 --- a/xmake/repository/templates/c++/module/binary/modules/binary/bar/src/sub.cpp +++ b/xmake/templates/c++/module/binary/modules/binary/bar/src/sub.cpp diff --git a/xmake/repository/templates/c++/module/binary/modules/binary/bar/xmake.lua b/xmake/templates/c++/module/binary/modules/binary/bar/xmake.lua index add3c6e97..add3c6e97 100644 --- a/xmake/repository/templates/c++/module/binary/modules/binary/bar/xmake.lua +++ b/xmake/templates/c++/module/binary/modules/binary/bar/xmake.lua diff --git a/xmake/repository/templates/c++/module/binary/src/main.cpp b/xmake/templates/c++/module/binary/src/main.cpp index 9b6abffea..9b6abffea 100644 --- a/xmake/repository/templates/c++/module/binary/src/main.cpp +++ b/xmake/templates/c++/module/binary/src/main.cpp diff --git a/xmake/repository/templates/c++/module/binary/xmake.lua b/xmake/templates/c++/module/binary/xmake.lua index d73d457d3..d73d457d3 100644 --- a/xmake/repository/templates/c++/module/binary/xmake.lua +++ b/xmake/templates/c++/module/binary/xmake.lua diff --git a/xmake/repository/templates/c++/module/shared/.gitignore b/xmake/templates/c++/module/shared/.gitignore index 152105761..152105761 100644 --- a/xmake/repository/templates/c++/module/shared/.gitignore +++ b/xmake/templates/c++/module/shared/.gitignore diff --git a/xmake/repository/templates/c++/module/shared/modules/shared/foo/src/foo.cpp b/xmake/templates/c++/module/shared/modules/shared/foo/src/foo.cpp index adde214ca..adde214ca 100644 --- a/xmake/repository/templates/c++/module/shared/modules/shared/foo/src/foo.cpp +++ b/xmake/templates/c++/module/shared/modules/shared/foo/src/foo.cpp diff --git a/xmake/repository/templates/c++/module/shared/modules/shared/foo/xmake.lua b/xmake/templates/c++/module/shared/modules/shared/foo/xmake.lua index 9b3423d41..9b3423d41 100644 --- a/xmake/repository/templates/c++/module/shared/modules/shared/foo/xmake.lua +++ b/xmake/templates/c++/module/shared/modules/shared/foo/xmake.lua diff --git a/xmake/repository/templates/c++/module/shared/src/main.cpp b/xmake/templates/c++/module/shared/src/main.cpp index 9b6abffea..9b6abffea 100644 --- a/xmake/repository/templates/c++/module/shared/src/main.cpp +++ b/xmake/templates/c++/module/shared/src/main.cpp diff --git a/xmake/repository/templates/c++/module/shared/xmake.lua b/xmake/templates/c++/module/shared/xmake.lua index 43aafe904..43aafe904 100644 --- a/xmake/repository/templates/c++/module/shared/xmake.lua +++ b/xmake/templates/c++/module/shared/xmake.lua diff --git a/xmake/repository/templates/c++/qt/console/src/main.cpp b/xmake/templates/c++/qt/console/src/main.cpp index e876eea4f..e876eea4f 100644 --- a/xmake/repository/templates/c++/qt/console/src/main.cpp +++ b/xmake/templates/c++/qt/console/src/main.cpp diff --git a/xmake/repository/templates/c++/qt/console/xmake.lua b/xmake/templates/c++/qt/console/xmake.lua index 2ce5aa993..2ce5aa993 100644 --- a/xmake/repository/templates/c++/qt/console/xmake.lua +++ b/xmake/templates/c++/qt/console/xmake.lua diff --git a/xmake/repository/templates/c++/qt/quickapp/src/main.cpp b/xmake/templates/c++/qt/quickapp/src/main.cpp index 7d9cb80df..7d9cb80df 100644 --- a/xmake/repository/templates/c++/qt/quickapp/src/main.cpp +++ b/xmake/templates/c++/qt/quickapp/src/main.cpp diff --git a/xmake/repository/templates/c++/qt/quickapp/src/main.qml b/xmake/templates/c++/qt/quickapp/src/main.qml index 120cdbddd..120cdbddd 100644 --- a/xmake/repository/templates/c++/qt/quickapp/src/main.qml +++ b/xmake/templates/c++/qt/quickapp/src/main.qml diff --git a/xmake/repository/templates/c++/qt/quickapp/src/qml.qrc b/xmake/templates/c++/qt/quickapp/src/qml.qrc index 5f6483ac3..5f6483ac3 100644 --- a/xmake/repository/templates/c++/qt/quickapp/src/qml.qrc +++ b/xmake/templates/c++/qt/quickapp/src/qml.qrc diff --git a/xmake/repository/templates/c++/qt/quickapp/xmake.lua b/xmake/templates/c++/qt/quickapp/xmake.lua index 3f71d1c15..3f71d1c15 100644 --- a/xmake/repository/templates/c++/qt/quickapp/xmake.lua +++ b/xmake/templates/c++/qt/quickapp/xmake.lua diff --git a/xmake/repository/templates/c++/qt/quickapp_static/src/main.cpp b/xmake/templates/c++/qt/quickapp_static/src/main.cpp index 7d9cb80df..7d9cb80df 100644 --- a/xmake/repository/templates/c++/qt/quickapp_static/src/main.cpp +++ b/xmake/templates/c++/qt/quickapp_static/src/main.cpp diff --git a/xmake/repository/templates/c++/qt/quickapp_static/src/main.qml b/xmake/templates/c++/qt/quickapp_static/src/main.qml index 120cdbddd..120cdbddd 100644 --- a/xmake/repository/templates/c++/qt/quickapp_static/src/main.qml +++ b/xmake/templates/c++/qt/quickapp_static/src/main.qml diff --git a/xmake/repository/templates/c++/qt/quickapp_static/src/qml.qrc b/xmake/templates/c++/qt/quickapp_static/src/qml.qrc index 5f6483ac3..5f6483ac3 100644 --- a/xmake/repository/templates/c++/qt/quickapp_static/src/qml.qrc +++ b/xmake/templates/c++/qt/quickapp_static/src/qml.qrc diff --git a/xmake/repository/templates/c++/qt/quickapp_static/xmake.lua b/xmake/templates/c++/qt/quickapp_static/xmake.lua index 0d311a762..0d311a762 100644 --- a/xmake/repository/templates/c++/qt/quickapp_static/xmake.lua +++ b/xmake/templates/c++/qt/quickapp_static/xmake.lua diff --git a/xmake/repository/templates/c++/qt/shared/src/demo.cpp b/xmake/templates/c++/qt/shared/src/demo.cpp index 576c861f0..576c861f0 100644 --- a/xmake/repository/templates/c++/qt/shared/src/demo.cpp +++ b/xmake/templates/c++/qt/shared/src/demo.cpp diff --git a/xmake/repository/templates/c++/qt/shared/src/demo.h b/xmake/templates/c++/qt/shared/src/demo.h index 89f29ec46..89f29ec46 100644 --- a/xmake/repository/templates/c++/qt/shared/src/demo.h +++ b/xmake/templates/c++/qt/shared/src/demo.h diff --git a/xmake/repository/templates/c++/qt/shared/src/demo_global.h b/xmake/templates/c++/qt/shared/src/demo_global.h index d6b1ddf0b..d6b1ddf0b 100644 --- a/xmake/repository/templates/c++/qt/shared/src/demo_global.h +++ b/xmake/templates/c++/qt/shared/src/demo_global.h diff --git a/xmake/repository/templates/c++/qt/shared/xmake.lua b/xmake/templates/c++/qt/shared/xmake.lua index 3b07153b9..3b07153b9 100644 --- a/xmake/repository/templates/c++/qt/shared/xmake.lua +++ b/xmake/templates/c++/qt/shared/xmake.lua diff --git a/xmake/repository/templates/c++/qt/static/src/demo.cpp b/xmake/templates/c++/qt/static/src/demo.cpp index 576c861f0..576c861f0 100644 --- a/xmake/repository/templates/c++/qt/static/src/demo.cpp +++ b/xmake/templates/c++/qt/static/src/demo.cpp diff --git a/xmake/repository/templates/c++/qt/static/src/demo.h b/xmake/templates/c++/qt/static/src/demo.h index 24730c9d8..24730c9d8 100644 --- a/xmake/repository/templates/c++/qt/static/src/demo.h +++ b/xmake/templates/c++/qt/static/src/demo.h diff --git a/xmake/repository/templates/c++/qt/static/xmake.lua b/xmake/templates/c++/qt/static/xmake.lua index 371bdf082..371bdf082 100644 --- a/xmake/repository/templates/c++/qt/static/xmake.lua +++ b/xmake/templates/c++/qt/static/xmake.lua diff --git a/xmake/repository/templates/c++/qt/widgetapp/src/main.cpp b/xmake/templates/c++/qt/widgetapp/src/main.cpp index 191ae18d2..191ae18d2 100644 --- a/xmake/repository/templates/c++/qt/widgetapp/src/main.cpp +++ b/xmake/templates/c++/qt/widgetapp/src/main.cpp diff --git a/xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.cpp b/xmake/templates/c++/qt/widgetapp/src/mainwindow.cpp index c9c6a0d98..c9c6a0d98 100644 --- a/xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.cpp +++ b/xmake/templates/c++/qt/widgetapp/src/mainwindow.cpp diff --git a/xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.h b/xmake/templates/c++/qt/widgetapp/src/mainwindow.h index a4245aa42..a4245aa42 100644 --- a/xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.h +++ b/xmake/templates/c++/qt/widgetapp/src/mainwindow.h diff --git a/xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.ui b/xmake/templates/c++/qt/widgetapp/src/mainwindow.ui index 1c59b695e..1c59b695e 100644 --- a/xmake/repository/templates/c++/qt/widgetapp/src/mainwindow.ui +++ b/xmake/templates/c++/qt/widgetapp/src/mainwindow.ui diff --git a/xmake/repository/templates/c++/qt/widgetapp/xmake.lua b/xmake/templates/c++/qt/widgetapp/xmake.lua index e0f9f455e..e0f9f455e 100644 --- a/xmake/repository/templates/c++/qt/widgetapp/xmake.lua +++ b/xmake/templates/c++/qt/widgetapp/xmake.lua diff --git a/xmake/repository/templates/c++/qt/widgetapp_static/src/main.cpp b/xmake/templates/c++/qt/widgetapp_static/src/main.cpp index db5b0cce8..db5b0cce8 100644 --- a/xmake/repository/templates/c++/qt/widgetapp_static/src/main.cpp +++ b/xmake/templates/c++/qt/widgetapp_static/src/main.cpp diff --git a/xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.cpp b/xmake/templates/c++/qt/widgetapp_static/src/mainwindow.cpp index c9c6a0d98..c9c6a0d98 100644 --- a/xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.cpp +++ b/xmake/templates/c++/qt/widgetapp_static/src/mainwindow.cpp diff --git a/xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.h b/xmake/templates/c++/qt/widgetapp_static/src/mainwindow.h index a4245aa42..a4245aa42 100644 --- a/xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.h +++ b/xmake/templates/c++/qt/widgetapp_static/src/mainwindow.h diff --git a/xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.ui b/xmake/templates/c++/qt/widgetapp_static/src/mainwindow.ui index 1c59b695e..1c59b695e 100644 --- a/xmake/repository/templates/c++/qt/widgetapp_static/src/mainwindow.ui +++ b/xmake/templates/c++/qt/widgetapp_static/src/mainwindow.ui diff --git a/xmake/repository/templates/c++/qt/widgetapp_static/xmake.lua b/xmake/templates/c++/qt/widgetapp_static/xmake.lua index 2c357e531..2c357e531 100644 --- a/xmake/repository/templates/c++/qt/widgetapp_static/xmake.lua +++ b/xmake/templates/c++/qt/widgetapp_static/xmake.lua diff --git a/xmake/repository/templates/c++/shared/src/foo.cpp b/xmake/templates/c++/shared/src/foo.cpp index 1a1fb3425..1a1fb3425 100644 --- a/xmake/repository/templates/c++/shared/src/foo.cpp +++ b/xmake/templates/c++/shared/src/foo.cpp diff --git a/xmake/repository/templates/c++/shared/src/foo.h b/xmake/templates/c++/shared/src/foo.h index bd496c784..bd496c784 100644 --- a/xmake/repository/templates/c++/shared/src/foo.h +++ b/xmake/templates/c++/shared/src/foo.h diff --git a/xmake/repository/templates/c++/shared/src/main.cpp b/xmake/templates/c++/shared/src/main.cpp index 3834ee4d3..3834ee4d3 100644 --- a/xmake/repository/templates/c++/shared/src/main.cpp +++ b/xmake/templates/c++/shared/src/main.cpp diff --git a/xmake/repository/templates/c++/shared/xmake.lua b/xmake/templates/c++/shared/xmake.lua index 96bd36d7c..96bd36d7c 100644 --- a/xmake/repository/templates/c++/shared/xmake.lua +++ b/xmake/templates/c++/shared/xmake.lua diff --git a/xmake/repository/templates/c++/static/src/foo.cpp b/xmake/templates/c++/static/src/foo.cpp index 1a1fb3425..1a1fb3425 100644 --- a/xmake/repository/templates/c++/static/src/foo.cpp +++ b/xmake/templates/c++/static/src/foo.cpp diff --git a/xmake/repository/templates/c++/static/src/foo.h b/xmake/templates/c++/static/src/foo.h index d2506bca9..d2506bca9 100644 --- a/xmake/repository/templates/c++/static/src/foo.h +++ b/xmake/templates/c++/static/src/foo.h diff --git a/xmake/repository/templates/c++/static/src/main.cpp b/xmake/templates/c++/static/src/main.cpp index 3834ee4d3..3834ee4d3 100644 --- a/xmake/repository/templates/c++/static/src/main.cpp +++ b/xmake/templates/c++/static/src/main.cpp diff --git a/xmake/repository/templates/c++/static/xmake.lua b/xmake/templates/c++/static/xmake.lua index 2c15d36e8..2c15d36e8 100644 --- a/xmake/repository/templates/c++/static/xmake.lua +++ b/xmake/templates/c++/static/xmake.lua diff --git a/xmake/repository/templates/c++/wxwidgets/src/main.cpp b/xmake/templates/c++/wxwidgets/src/main.cpp index 4b43fe6e3..4b43fe6e3 100644 --- a/xmake/repository/templates/c++/wxwidgets/src/main.cpp +++ b/xmake/templates/c++/wxwidgets/src/main.cpp diff --git a/xmake/repository/templates/c++/wxwidgets/xmake.lua b/xmake/templates/c++/wxwidgets/xmake.lua index 65a05c72c..65a05c72c 100644 --- a/xmake/repository/templates/c++/wxwidgets/xmake.lua +++ b/xmake/templates/c++/wxwidgets/xmake.lua diff --git a/xmake/repository/templates/c++/xmake/cli/src/lni/main.cpp b/xmake/templates/c++/xmake/cli/src/lni/main.cpp index 6dd5b81b1..6dd5b81b1 100644 --- a/xmake/repository/templates/c++/xmake/cli/src/lni/main.cpp +++ b/xmake/templates/c++/xmake/cli/src/lni/main.cpp diff --git a/xmake/repository/templates/c++/xmake/cli/src/lua/main.lua b/xmake/templates/c++/xmake/cli/src/lua/main.lua index d87daf102..d87daf102 100644 --- a/xmake/repository/templates/c++/xmake/cli/src/lua/main.lua +++ b/xmake/templates/c++/xmake/cli/src/lua/main.lua diff --git a/xmake/repository/templates/c++/xmake/cli/xmake.lua b/xmake/templates/c++/xmake/cli/xmake.lua index cf1987c60..cf1987c60 100644 --- a/xmake/repository/templates/c++/xmake/cli/xmake.lua +++ b/xmake/templates/c++/xmake/cli/xmake.lua diff --git a/xmake/repository/templates/c/console/src/main.c b/xmake/templates/c/console/src/main.c index ccf4b2a77..ccf4b2a77 100644 --- a/xmake/repository/templates/c/console/src/main.c +++ b/xmake/templates/c/console/src/main.c diff --git a/xmake/repository/templates/c/console/xmake.lua b/xmake/templates/c/console/xmake.lua index 7e9356f26..7e9356f26 100644 --- a/xmake/repository/templates/c/console/xmake.lua +++ b/xmake/templates/c/console/xmake.lua diff --git a/xmake/repository/templates/c/module/binary/.gitignore b/xmake/templates/c/module/binary/.gitignore index 152105761..152105761 100644 --- a/xmake/repository/templates/c/module/binary/.gitignore +++ b/xmake/templates/c/module/binary/.gitignore diff --git a/xmake/repository/templates/c/module/binary/modules/binary/bar/.gitignore b/xmake/templates/c/module/binary/modules/binary/bar/.gitignore index 152105761..152105761 100644 --- a/xmake/repository/templates/c/module/binary/modules/binary/bar/.gitignore +++ b/xmake/templates/c/module/binary/modules/binary/bar/.gitignore diff --git a/xmake/repository/templates/c/module/binary/modules/binary/bar/src/add.c b/xmake/templates/c/module/binary/modules/binary/bar/src/add.c index 93fdf0ad8..93fdf0ad8 100644 --- a/xmake/repository/templates/c/module/binary/modules/binary/bar/src/add.c +++ b/xmake/templates/c/module/binary/modules/binary/bar/src/add.c diff --git a/xmake/repository/templates/c/module/binary/modules/binary/bar/src/sub.c b/xmake/templates/c/module/binary/modules/binary/bar/src/sub.c index ae7b6d1f2..ae7b6d1f2 100644 --- a/xmake/repository/templates/c/module/binary/modules/binary/bar/src/sub.c +++ b/xmake/templates/c/module/binary/modules/binary/bar/src/sub.c diff --git a/xmake/repository/templates/c/module/binary/modules/binary/bar/xmake.lua b/xmake/templates/c/module/binary/modules/binary/bar/xmake.lua index d4983d741..d4983d741 100644 --- a/xmake/repository/templates/c/module/binary/modules/binary/bar/xmake.lua +++ b/xmake/templates/c/module/binary/modules/binary/bar/xmake.lua diff --git a/xmake/repository/templates/c/module/binary/src/main.c b/xmake/templates/c/module/binary/src/main.c index ccf4b2a77..ccf4b2a77 100644 --- a/xmake/repository/templates/c/module/binary/src/main.c +++ b/xmake/templates/c/module/binary/src/main.c diff --git a/xmake/repository/templates/c/module/binary/xmake.lua b/xmake/templates/c/module/binary/xmake.lua index 7df556cb8..7df556cb8 100644 --- a/xmake/repository/templates/c/module/binary/xmake.lua +++ b/xmake/templates/c/module/binary/xmake.lua diff --git a/xmake/repository/templates/c/module/shared/.gitignore b/xmake/templates/c/module/shared/.gitignore index 152105761..152105761 100644 --- a/xmake/repository/templates/c/module/shared/.gitignore +++ b/xmake/templates/c/module/shared/.gitignore diff --git a/xmake/repository/templates/c/module/shared/modules/shared/foo/src/foo.c b/xmake/templates/c/module/shared/modules/shared/foo/src/foo.c index adde214ca..adde214ca 100644 --- a/xmake/repository/templates/c/module/shared/modules/shared/foo/src/foo.c +++ b/xmake/templates/c/module/shared/modules/shared/foo/src/foo.c diff --git a/xmake/repository/templates/c/module/shared/modules/shared/foo/xmake.lua b/xmake/templates/c/module/shared/modules/shared/foo/xmake.lua index 035573d9f..035573d9f 100644 --- a/xmake/repository/templates/c/module/shared/modules/shared/foo/xmake.lua +++ b/xmake/templates/c/module/shared/modules/shared/foo/xmake.lua diff --git a/xmake/repository/templates/c/module/shared/src/main.c b/xmake/templates/c/module/shared/src/main.c index ccf4b2a77..ccf4b2a77 100644 --- a/xmake/repository/templates/c/module/shared/src/main.c +++ b/xmake/templates/c/module/shared/src/main.c diff --git a/xmake/repository/templates/c/module/shared/xmake.lua b/xmake/templates/c/module/shared/xmake.lua index 4b92b0b9e..4b92b0b9e 100644 --- a/xmake/repository/templates/c/module/shared/xmake.lua +++ b/xmake/templates/c/module/shared/xmake.lua diff --git a/xmake/repository/templates/c/shared/src/foo.c b/xmake/templates/c/shared/src/foo.c index 1a1fb3425..1a1fb3425 100644 --- a/xmake/repository/templates/c/shared/src/foo.c +++ b/xmake/templates/c/shared/src/foo.c diff --git a/xmake/repository/templates/c/shared/src/foo.h b/xmake/templates/c/shared/src/foo.h index e15925829..e15925829 100644 --- a/xmake/repository/templates/c/shared/src/foo.h +++ b/xmake/templates/c/shared/src/foo.h diff --git a/xmake/repository/templates/c/shared/src/main.c b/xmake/templates/c/shared/src/main.c index f1c29d751..f1c29d751 100644 --- a/xmake/repository/templates/c/shared/src/main.c +++ b/xmake/templates/c/shared/src/main.c diff --git a/xmake/repository/templates/c/shared/xmake.lua b/xmake/templates/c/shared/xmake.lua index 11e8dd0dd..11e8dd0dd 100644 --- a/xmake/repository/templates/c/shared/xmake.lua +++ b/xmake/templates/c/shared/xmake.lua diff --git a/xmake/repository/templates/c/static/src/foo.c b/xmake/templates/c/static/src/foo.c index 1a1fb3425..1a1fb3425 100644 --- a/xmake/repository/templates/c/static/src/foo.c +++ b/xmake/templates/c/static/src/foo.c diff --git a/xmake/repository/templates/c/static/src/foo.h b/xmake/templates/c/static/src/foo.h index 6295ab95c..6295ab95c 100644 --- a/xmake/repository/templates/c/static/src/foo.h +++ b/xmake/templates/c/static/src/foo.h diff --git a/xmake/repository/templates/c/static/src/main.c b/xmake/templates/c/static/src/main.c index f1c29d751..f1c29d751 100644 --- a/xmake/repository/templates/c/static/src/main.c +++ b/xmake/templates/c/static/src/main.c diff --git a/xmake/repository/templates/c/static/xmake.lua b/xmake/templates/c/static/xmake.lua index f00e9f4f7..f00e9f4f7 100644 --- a/xmake/repository/templates/c/static/xmake.lua +++ b/xmake/templates/c/static/xmake.lua diff --git a/xmake/repository/templates/c/xmake/cli/src/lni/main.c b/xmake/templates/c/xmake/cli/src/lni/main.c index b1cef4e40..b1cef4e40 100644 --- a/xmake/repository/templates/c/xmake/cli/src/lni/main.c +++ b/xmake/templates/c/xmake/cli/src/lni/main.c diff --git a/xmake/repository/templates/c/xmake/cli/src/lua/main.lua b/xmake/templates/c/xmake/cli/src/lua/main.lua index d87daf102..d87daf102 100644 --- a/xmake/repository/templates/c/xmake/cli/src/lua/main.lua +++ b/xmake/templates/c/xmake/cli/src/lua/main.lua diff --git a/xmake/repository/templates/c/xmake/cli/xmake.lua b/xmake/templates/c/xmake/cli/xmake.lua index 33422b5c0..33422b5c0 100644 --- a/xmake/repository/templates/c/xmake/cli/xmake.lua +++ b/xmake/templates/c/xmake/cli/xmake.lua diff --git a/xmake/repository/templates/csharp/console/src/Program.cs b/xmake/templates/csharp/console/src/Program.cs index 5f75209cb..5f75209cb 100644 --- a/xmake/repository/templates/csharp/console/src/Program.cs +++ b/xmake/templates/csharp/console/src/Program.cs diff --git a/xmake/repository/templates/csharp/console/xmake.lua b/xmake/templates/csharp/console/xmake.lua index d19ce0fcd..d19ce0fcd 100644 --- a/xmake/repository/templates/csharp/console/xmake.lua +++ b/xmake/templates/csharp/console/xmake.lua diff --git a/xmake/repository/templates/csharp/shared/src/foo.cs b/xmake/templates/csharp/shared/src/foo.cs index bba30d999..bba30d999 100644 --- a/xmake/repository/templates/csharp/shared/src/foo.cs +++ b/xmake/templates/csharp/shared/src/foo.cs diff --git a/xmake/repository/templates/csharp/shared/src/main.cs b/xmake/templates/csharp/shared/src/main.cs index c2e4eb2fd..c2e4eb2fd 100644 --- a/xmake/repository/templates/csharp/shared/src/main.cs +++ b/xmake/templates/csharp/shared/src/main.cs diff --git a/xmake/repository/templates/csharp/shared/xmake.lua b/xmake/templates/csharp/shared/xmake.lua index 256ed0f65..256ed0f65 100644 --- a/xmake/repository/templates/csharp/shared/xmake.lua +++ b/xmake/templates/csharp/shared/xmake.lua diff --git a/xmake/repository/templates/csharp/static/src/foo.cs b/xmake/templates/csharp/static/src/foo.cs index bba30d999..bba30d999 100644 --- a/xmake/repository/templates/csharp/static/src/foo.cs +++ b/xmake/templates/csharp/static/src/foo.cs diff --git a/xmake/repository/templates/csharp/static/src/main.cs b/xmake/templates/csharp/static/src/main.cs index c2e4eb2fd..c2e4eb2fd 100644 --- a/xmake/repository/templates/csharp/static/src/main.cs +++ b/xmake/templates/csharp/static/src/main.cs diff --git a/xmake/repository/templates/csharp/static/xmake.lua b/xmake/templates/csharp/static/xmake.lua index 51bce92a0..51bce92a0 100644 --- a/xmake/repository/templates/csharp/static/xmake.lua +++ b/xmake/templates/csharp/static/xmake.lua diff --git a/xmake/repository/templates/cuda/console/src/main.cu b/xmake/templates/cuda/console/src/main.cu index 2fe9ac797..2fe9ac797 100644 --- a/xmake/repository/templates/cuda/console/src/main.cu +++ b/xmake/templates/cuda/console/src/main.cu diff --git a/xmake/repository/templates/cuda/console/xmake.lua b/xmake/templates/cuda/console/xmake.lua index fb393bab7..fb393bab7 100644 --- a/xmake/repository/templates/cuda/console/xmake.lua +++ b/xmake/templates/cuda/console/xmake.lua diff --git a/xmake/repository/templates/cuda/shared/inc/lib.cuh b/xmake/templates/cuda/shared/inc/lib.cuh index 5565e3eb5..5565e3eb5 100644 --- a/xmake/repository/templates/cuda/shared/inc/lib.cuh +++ b/xmake/templates/cuda/shared/inc/lib.cuh diff --git a/xmake/repository/templates/cuda/shared/src/lib.cu b/xmake/templates/cuda/shared/src/lib.cu index d2cff9ac2..d2cff9ac2 100644 --- a/xmake/repository/templates/cuda/shared/src/lib.cu +++ b/xmake/templates/cuda/shared/src/lib.cu diff --git a/xmake/repository/templates/cuda/shared/xmake.lua b/xmake/templates/cuda/shared/xmake.lua index 5f53ff87b..5f53ff87b 100644 --- a/xmake/repository/templates/cuda/shared/xmake.lua +++ b/xmake/templates/cuda/shared/xmake.lua diff --git a/xmake/repository/templates/cuda/static/inc/lib.cuh b/xmake/templates/cuda/static/inc/lib.cuh index 35255e31e..35255e31e 100644 --- a/xmake/repository/templates/cuda/static/inc/lib.cuh +++ b/xmake/templates/cuda/static/inc/lib.cuh diff --git a/xmake/repository/templates/cuda/static/src/lib.cu b/xmake/templates/cuda/static/src/lib.cu index a5f054354..a5f054354 100644 --- a/xmake/repository/templates/cuda/static/src/lib.cu +++ b/xmake/templates/cuda/static/src/lib.cu diff --git a/xmake/repository/templates/cuda/static/xmake.lua b/xmake/templates/cuda/static/xmake.lua index 7a582cfbb..7a582cfbb 100644 --- a/xmake/repository/templates/cuda/static/xmake.lua +++ b/xmake/templates/cuda/static/xmake.lua diff --git a/xmake/repository/templates/dlang/console/src/main.d b/xmake/templates/dlang/console/src/main.d index 6bea6ec02..6bea6ec02 100644 --- a/xmake/repository/templates/dlang/console/src/main.d +++ b/xmake/templates/dlang/console/src/main.d diff --git a/xmake/repository/templates/dlang/console/xmake.lua b/xmake/templates/dlang/console/xmake.lua index c242d60c2..c242d60c2 100644 --- a/xmake/repository/templates/dlang/console/xmake.lua +++ b/xmake/templates/dlang/console/xmake.lua diff --git a/xmake/repository/templates/dlang/shared/src/interfaces.d b/xmake/templates/dlang/shared/src/interfaces.d index b4f7ab6ba..b4f7ab6ba 100644 --- a/xmake/repository/templates/dlang/shared/src/interfaces.d +++ b/xmake/templates/dlang/shared/src/interfaces.d diff --git a/xmake/repository/templates/dlang/shared/src/main.d b/xmake/templates/dlang/shared/src/main.d index bfcf9cf56..bfcf9cf56 100644 --- a/xmake/repository/templates/dlang/shared/src/main.d +++ b/xmake/templates/dlang/shared/src/main.d diff --git a/xmake/repository/templates/dlang/shared/xmake.lua b/xmake/templates/dlang/shared/xmake.lua index 0086bebae..0086bebae 100644 --- a/xmake/repository/templates/dlang/shared/xmake.lua +++ b/xmake/templates/dlang/shared/xmake.lua diff --git a/xmake/repository/templates/dlang/static/src/interfaces.d b/xmake/templates/dlang/static/src/interfaces.d index 3386c9124..3386c9124 100644 --- a/xmake/repository/templates/dlang/static/src/interfaces.d +++ b/xmake/templates/dlang/static/src/interfaces.d diff --git a/xmake/repository/templates/dlang/static/src/main.d b/xmake/templates/dlang/static/src/main.d index bfcf9cf56..bfcf9cf56 100644 --- a/xmake/repository/templates/dlang/static/src/main.d +++ b/xmake/templates/dlang/static/src/main.d diff --git a/xmake/repository/templates/dlang/static/xmake.lua b/xmake/templates/dlang/static/xmake.lua index b8fb24b37..b8fb24b37 100644 --- a/xmake/repository/templates/dlang/static/xmake.lua +++ b/xmake/templates/dlang/static/xmake.lua diff --git a/xmake/repository/templates/fortran/console/src/main.f90 b/xmake/templates/fortran/console/src/main.f90 index a332e8401..a332e8401 100644 --- a/xmake/repository/templates/fortran/console/src/main.f90 +++ b/xmake/templates/fortran/console/src/main.f90 diff --git a/xmake/repository/templates/fortran/console/xmake.lua b/xmake/templates/fortran/console/xmake.lua index 70faf8aea..70faf8aea 100644 --- a/xmake/repository/templates/fortran/console/xmake.lua +++ b/xmake/templates/fortran/console/xmake.lua diff --git a/xmake/repository/templates/fortran/shared/src/main.f90 b/xmake/templates/fortran/shared/src/main.f90 index 9adea3e26..9adea3e26 100644 --- a/xmake/repository/templates/fortran/shared/src/main.f90 +++ b/xmake/templates/fortran/shared/src/main.f90 diff --git a/xmake/repository/templates/fortran/shared/src/test.f90 b/xmake/templates/fortran/shared/src/test.f90 index 7b215fcdf..7b215fcdf 100644 --- a/xmake/repository/templates/fortran/shared/src/test.f90 +++ b/xmake/templates/fortran/shared/src/test.f90 diff --git a/xmake/repository/templates/fortran/shared/xmake.lua b/xmake/templates/fortran/shared/xmake.lua index da6d6da3f..da6d6da3f 100644 --- a/xmake/repository/templates/fortran/shared/xmake.lua +++ b/xmake/templates/fortran/shared/xmake.lua diff --git a/xmake/repository/templates/fortran/static/src/main.f90 b/xmake/templates/fortran/static/src/main.f90 index 9adea3e26..9adea3e26 100644 --- a/xmake/repository/templates/fortran/static/src/main.f90 +++ b/xmake/templates/fortran/static/src/main.f90 diff --git a/xmake/repository/templates/fortran/static/src/test.f90 b/xmake/templates/fortran/static/src/test.f90 index 7b215fcdf..7b215fcdf 100644 --- a/xmake/repository/templates/fortran/static/src/test.f90 +++ b/xmake/templates/fortran/static/src/test.f90 diff --git a/xmake/repository/templates/fortran/static/xmake.lua b/xmake/templates/fortran/static/xmake.lua index 4b91ad207..4b91ad207 100644 --- a/xmake/repository/templates/fortran/static/xmake.lua +++ b/xmake/templates/fortran/static/xmake.lua diff --git a/xmake/repository/templates/go/console/src/main.go b/xmake/templates/go/console/src/main.go index b689db480..b689db480 100644 --- a/xmake/repository/templates/go/console/src/main.go +++ b/xmake/templates/go/console/src/main.go diff --git a/xmake/repository/templates/go/console/xmake.lua b/xmake/templates/go/console/xmake.lua index a7861eb2a..a7861eb2a 100644 --- a/xmake/repository/templates/go/console/xmake.lua +++ b/xmake/templates/go/console/xmake.lua diff --git a/xmake/repository/templates/go/static/src/main.go b/xmake/templates/go/static/src/main.go index f2b477453..f2b477453 100644 --- a/xmake/repository/templates/go/static/src/main.go +++ b/xmake/templates/go/static/src/main.go diff --git a/xmake/repository/templates/go/static/src/module/add.go b/xmake/templates/go/static/src/module/add.go index 98ffef600..98ffef600 100644 --- a/xmake/repository/templates/go/static/src/module/add.go +++ b/xmake/templates/go/static/src/module/add.go diff --git a/xmake/repository/templates/go/static/src/module/sub.go b/xmake/templates/go/static/src/module/sub.go index a24a9abb7..a24a9abb7 100644 --- a/xmake/repository/templates/go/static/src/module/sub.go +++ b/xmake/templates/go/static/src/module/sub.go diff --git a/xmake/repository/templates/go/static/src/test.go b/xmake/templates/go/static/src/test.go index cf10523f9..cf10523f9 100644 --- a/xmake/repository/templates/go/static/src/test.go +++ b/xmake/templates/go/static/src/test.go diff --git a/xmake/repository/templates/go/static/xmake.lua b/xmake/templates/go/static/xmake.lua index 4391d7799..4391d7799 100644 --- a/xmake/repository/templates/go/static/xmake.lua +++ b/xmake/templates/go/static/xmake.lua diff --git a/xmake/repository/templates/kotlin/console/src/main.kt b/xmake/templates/kotlin/console/src/main.kt index 543f5ac8f..543f5ac8f 100644 --- a/xmake/repository/templates/kotlin/console/src/main.kt +++ b/xmake/templates/kotlin/console/src/main.kt diff --git a/xmake/repository/templates/kotlin/console/xmake.lua b/xmake/templates/kotlin/console/xmake.lua index 935dc7c75..935dc7c75 100644 --- a/xmake/repository/templates/kotlin/console/xmake.lua +++ b/xmake/templates/kotlin/console/xmake.lua diff --git a/xmake/repository/templates/kotlin/shared/src/foo.kt b/xmake/templates/kotlin/shared/src/foo.kt index cc5184bd7..cc5184bd7 100644 --- a/xmake/repository/templates/kotlin/shared/src/foo.kt +++ b/xmake/templates/kotlin/shared/src/foo.kt diff --git a/xmake/repository/templates/kotlin/shared/src/main.c b/xmake/templates/kotlin/shared/src/main.c index abb3f2c12..abb3f2c12 100644 --- a/xmake/repository/templates/kotlin/shared/src/main.c +++ b/xmake/templates/kotlin/shared/src/main.c diff --git a/xmake/repository/templates/kotlin/shared/xmake.lua b/xmake/templates/kotlin/shared/xmake.lua index 97bebf8a6..97bebf8a6 100644 --- a/xmake/repository/templates/kotlin/shared/xmake.lua +++ b/xmake/templates/kotlin/shared/xmake.lua diff --git a/xmake/repository/templates/kotlin/static/src/foo.kt b/xmake/templates/kotlin/static/src/foo.kt index cc5184bd7..cc5184bd7 100644 --- a/xmake/repository/templates/kotlin/static/src/foo.kt +++ b/xmake/templates/kotlin/static/src/foo.kt diff --git a/xmake/repository/templates/kotlin/static/src/main.c b/xmake/templates/kotlin/static/src/main.c index abb3f2c12..abb3f2c12 100644 --- a/xmake/repository/templates/kotlin/static/src/main.c +++ b/xmake/templates/kotlin/static/src/main.c diff --git a/xmake/repository/templates/kotlin/static/xmake.lua b/xmake/templates/kotlin/static/xmake.lua index 6095dbe93..6095dbe93 100644 --- a/xmake/repository/templates/kotlin/static/xmake.lua +++ b/xmake/templates/kotlin/static/xmake.lua diff --git a/xmake/repository/templates/nim/console/src/main.nim b/xmake/templates/nim/console/src/main.nim index 17179284f..17179284f 100644 --- a/xmake/repository/templates/nim/console/src/main.nim +++ b/xmake/templates/nim/console/src/main.nim diff --git a/xmake/repository/templates/nim/console/xmake.lua b/xmake/templates/nim/console/xmake.lua index 662945bbb..662945bbb 100644 --- a/xmake/repository/templates/nim/console/xmake.lua +++ b/xmake/templates/nim/console/xmake.lua diff --git a/xmake/repository/templates/nim/shared/src/foo.nim b/xmake/templates/nim/shared/src/foo.nim index cde4de7ca..cde4de7ca 100644 --- a/xmake/repository/templates/nim/shared/src/foo.nim +++ b/xmake/templates/nim/shared/src/foo.nim diff --git a/xmake/repository/templates/nim/shared/src/main.nim b/xmake/templates/nim/shared/src/main.nim index 1be3abe69..1be3abe69 100644 --- a/xmake/repository/templates/nim/shared/src/main.nim +++ b/xmake/templates/nim/shared/src/main.nim diff --git a/xmake/repository/templates/nim/shared/xmake.lua b/xmake/templates/nim/shared/xmake.lua index 5067dafb3..5067dafb3 100644 --- a/xmake/repository/templates/nim/shared/xmake.lua +++ b/xmake/templates/nim/shared/xmake.lua diff --git a/xmake/repository/templates/nim/static/src/foo.nim b/xmake/templates/nim/static/src/foo.nim index be0904262..be0904262 100644 --- a/xmake/repository/templates/nim/static/src/foo.nim +++ b/xmake/templates/nim/static/src/foo.nim diff --git a/xmake/repository/templates/nim/static/src/main.nim b/xmake/templates/nim/static/src/main.nim index 1be3abe69..1be3abe69 100644 --- a/xmake/repository/templates/nim/static/src/main.nim +++ b/xmake/templates/nim/static/src/main.nim diff --git a/xmake/repository/templates/nim/static/xmake.lua b/xmake/templates/nim/static/xmake.lua index 3f2cb7dfc..3f2cb7dfc 100644 --- a/xmake/repository/templates/nim/static/xmake.lua +++ b/xmake/templates/nim/static/xmake.lua diff --git a/xmake/repository/templates/objc++/console/src/main.mm b/xmake/templates/objc++/console/src/main.mm index cbd1e8906..cbd1e8906 100644 --- a/xmake/repository/templates/objc++/console/src/main.mm +++ b/xmake/templates/objc++/console/src/main.mm diff --git a/xmake/repository/templates/objc++/console/xmake.lua b/xmake/templates/objc++/console/xmake.lua index 99749f901..99749f901 100644 --- a/xmake/repository/templates/objc++/console/xmake.lua +++ b/xmake/templates/objc++/console/xmake.lua diff --git a/xmake/repository/templates/objc++/xcode/bundle/src/Info.plist b/xmake/templates/objc++/xcode/bundle/src/Info.plist index 20608314e..20608314e 100644 --- a/xmake/repository/templates/objc++/xcode/bundle/src/Info.plist +++ b/xmake/templates/objc++/xcode/bundle/src/Info.plist diff --git a/xmake/repository/templates/objc++/xcode/bundle/src/test.h b/xmake/templates/objc++/xcode/bundle/src/test.h index d882546d1..d882546d1 100644 --- a/xmake/repository/templates/objc++/xcode/bundle/src/test.h +++ b/xmake/templates/objc++/xcode/bundle/src/test.h diff --git a/xmake/repository/templates/objc++/xcode/bundle/src/test.mm b/xmake/templates/objc++/xcode/bundle/src/test.mm index 20e29bd0a..20e29bd0a 100644 --- a/xmake/repository/templates/objc++/xcode/bundle/src/test.mm +++ b/xmake/templates/objc++/xcode/bundle/src/test.mm diff --git a/xmake/repository/templates/objc++/xcode/bundle/xmake.lua b/xmake/templates/objc++/xcode/bundle/xmake.lua index 1ecf69fcb..1ecf69fcb 100644 --- a/xmake/repository/templates/objc++/xcode/bundle/xmake.lua +++ b/xmake/templates/objc++/xcode/bundle/xmake.lua diff --git a/xmake/repository/templates/objc++/xcode/framework/src/Info.plist b/xmake/templates/objc++/xcode/framework/src/Info.plist index 20608314e..20608314e 100644 --- a/xmake/repository/templates/objc++/xcode/framework/src/Info.plist +++ b/xmake/templates/objc++/xcode/framework/src/Info.plist diff --git a/xmake/repository/templates/objc++/xcode/framework/src/test.h b/xmake/templates/objc++/xcode/framework/src/test.h index d882546d1..d882546d1 100644 --- a/xmake/repository/templates/objc++/xcode/framework/src/test.h +++ b/xmake/templates/objc++/xcode/framework/src/test.h diff --git a/xmake/repository/templates/objc++/xcode/framework/src/test.mm b/xmake/templates/objc++/xcode/framework/src/test.mm index 20e29bd0a..20e29bd0a 100644 --- a/xmake/repository/templates/objc++/xcode/framework/src/test.mm +++ b/xmake/templates/objc++/xcode/framework/src/test.mm diff --git a/xmake/repository/templates/objc++/xcode/framework/xmake.lua b/xmake/templates/objc++/xcode/framework/xmake.lua index 3805d95c6..3805d95c6 100644 --- a/xmake/repository/templates/objc++/xcode/framework/xmake.lua +++ b/xmake/templates/objc++/xcode/framework/xmake.lua diff --git a/xmake/repository/templates/objc/console/src/main.m b/xmake/templates/objc/console/src/main.m index cbd1e8906..cbd1e8906 100644 --- a/xmake/repository/templates/objc/console/src/main.m +++ b/xmake/templates/objc/console/src/main.m diff --git a/xmake/repository/templates/objc/console/xmake.lua b/xmake/templates/objc/console/xmake.lua index 37c01442a..37c01442a 100644 --- a/xmake/repository/templates/objc/console/xmake.lua +++ b/xmake/templates/objc/console/xmake.lua diff --git a/xmake/repository/templates/objc/xcode/bundle/src/Info.plist b/xmake/templates/objc/xcode/bundle/src/Info.plist index 20608314e..20608314e 100644 --- a/xmake/repository/templates/objc/xcode/bundle/src/Info.plist +++ b/xmake/templates/objc/xcode/bundle/src/Info.plist diff --git a/xmake/repository/templates/objc/xcode/bundle/src/test.h b/xmake/templates/objc/xcode/bundle/src/test.h index d882546d1..d882546d1 100644 --- a/xmake/repository/templates/objc/xcode/bundle/src/test.h +++ b/xmake/templates/objc/xcode/bundle/src/test.h diff --git a/xmake/repository/templates/objc/xcode/bundle/src/test.m b/xmake/templates/objc/xcode/bundle/src/test.m index 20e29bd0a..20e29bd0a 100644 --- a/xmake/repository/templates/objc/xcode/bundle/src/test.m +++ b/xmake/templates/objc/xcode/bundle/src/test.m diff --git a/xmake/repository/templates/objc/xcode/bundle/xmake.lua b/xmake/templates/objc/xcode/bundle/xmake.lua index 34d108fcb..34d108fcb 100644 --- a/xmake/repository/templates/objc/xcode/bundle/xmake.lua +++ b/xmake/templates/objc/xcode/bundle/xmake.lua diff --git a/xmake/repository/templates/objc/xcode/framework/src/Info.plist b/xmake/templates/objc/xcode/framework/src/Info.plist index 20608314e..20608314e 100644 --- a/xmake/repository/templates/objc/xcode/framework/src/Info.plist +++ b/xmake/templates/objc/xcode/framework/src/Info.plist diff --git a/xmake/repository/templates/objc/xcode/framework/src/test.h b/xmake/templates/objc/xcode/framework/src/test.h index d882546d1..d882546d1 100644 --- a/xmake/repository/templates/objc/xcode/framework/src/test.h +++ b/xmake/templates/objc/xcode/framework/src/test.h diff --git a/xmake/repository/templates/objc/xcode/framework/src/test.m b/xmake/templates/objc/xcode/framework/src/test.m index 20e29bd0a..20e29bd0a 100644 --- a/xmake/repository/templates/objc/xcode/framework/src/test.m +++ b/xmake/templates/objc/xcode/framework/src/test.m diff --git a/xmake/repository/templates/objc/xcode/framework/xmake.lua b/xmake/templates/objc/xcode/framework/xmake.lua index 83ddfa1a2..83ddfa1a2 100644 --- a/xmake/repository/templates/objc/xcode/framework/xmake.lua +++ b/xmake/templates/objc/xcode/framework/xmake.lua diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/AppDelegate.h b/xmake/templates/objc/xcode/iosapp/src/AppDelegate.h index b01a8dc72..b01a8dc72 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/AppDelegate.h +++ b/xmake/templates/objc/xcode/iosapp/src/AppDelegate.h diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/AppDelegate.m b/xmake/templates/objc/xcode/iosapp/src/AppDelegate.m index 0ad500bfe..0ad500bfe 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/AppDelegate.m +++ b/xmake/templates/objc/xcode/iosapp/src/AppDelegate.m diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json b/xmake/templates/objc/xcode/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json index d8db8d65f..d8db8d65f 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/xmake/templates/objc/xcode/iosapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/Assets.xcassets/Contents.json b/xmake/templates/objc/xcode/iosapp/src/Assets.xcassets/Contents.json index da4a164c9..da4a164c9 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/Assets.xcassets/Contents.json +++ b/xmake/templates/objc/xcode/iosapp/src/Assets.xcassets/Contents.json diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/Base.lproj/LaunchScreen.storyboard b/xmake/templates/objc/xcode/iosapp/src/Base.lproj/LaunchScreen.storyboard index 865e9329f..865e9329f 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/Base.lproj/LaunchScreen.storyboard +++ b/xmake/templates/objc/xcode/iosapp/src/Base.lproj/LaunchScreen.storyboard diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/Base.lproj/Main.storyboard b/xmake/templates/objc/xcode/iosapp/src/Base.lproj/Main.storyboard index 808a21ce7..808a21ce7 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/Base.lproj/Main.storyboard +++ b/xmake/templates/objc/xcode/iosapp/src/Base.lproj/Main.storyboard diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/Info.plist b/xmake/templates/objc/xcode/iosapp/src/Info.plist index 686d21a3a..686d21a3a 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/Info.plist +++ b/xmake/templates/objc/xcode/iosapp/src/Info.plist diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/SceneDelegate.h b/xmake/templates/objc/xcode/iosapp/src/SceneDelegate.h index 5dbf88aa6..5dbf88aa6 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/SceneDelegate.h +++ b/xmake/templates/objc/xcode/iosapp/src/SceneDelegate.h diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/SceneDelegate.m b/xmake/templates/objc/xcode/iosapp/src/SceneDelegate.m index d6698dd7c..d6698dd7c 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/SceneDelegate.m +++ b/xmake/templates/objc/xcode/iosapp/src/SceneDelegate.m diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/ViewController.h b/xmake/templates/objc/xcode/iosapp/src/ViewController.h index e74d2f236..e74d2f236 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/ViewController.h +++ b/xmake/templates/objc/xcode/iosapp/src/ViewController.h diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/ViewController.m b/xmake/templates/objc/xcode/iosapp/src/ViewController.m index c3441c87a..c3441c87a 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/ViewController.m +++ b/xmake/templates/objc/xcode/iosapp/src/ViewController.m diff --git a/xmake/repository/templates/objc/xcode/iosapp/src/main.m b/xmake/templates/objc/xcode/iosapp/src/main.m index 11a58afc7..11a58afc7 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/src/main.m +++ b/xmake/templates/objc/xcode/iosapp/src/main.m diff --git a/xmake/repository/templates/objc/xcode/iosapp/xmake.lua b/xmake/templates/objc/xcode/iosapp/xmake.lua index 1306fce94..1306fce94 100644 --- a/xmake/repository/templates/objc/xcode/iosapp/xmake.lua +++ b/xmake/templates/objc/xcode/iosapp/xmake.lua diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.h b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.h index b01a8dc72..b01a8dc72 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.h +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.h diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.m b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.m index 1f3556c06..1f3556c06 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.m +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/AppDelegate.m diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json index d8db8d65f..d8db8d65f 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/Contents.json b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/Contents.json index da4a164c9..da4a164c9 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/Contents.json +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Assets.xcassets/Contents.json diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard index 865e9329f..865e9329f 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/LaunchScreen.storyboard diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/Main.storyboard b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/Main.storyboard index 808a21ce7..808a21ce7 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/Main.storyboard +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Base.lproj/Main.storyboard diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Info.plist b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Info.plist index 686d21a3a..686d21a3a 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/Info.plist +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/Info.plist diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.h b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.h index 5dbf88aa6..5dbf88aa6 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.h +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.h diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.m b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.m index d6698dd7c..d6698dd7c 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.m +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/SceneDelegate.m diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.h b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.h index e74d2f236..e74d2f236 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.h +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.h diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.m b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.m index c3441c87a..c3441c87a 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.m +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/ViewController.m diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/main.m b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/main.m index 11a58afc7..11a58afc7 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/app/main.m +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/app/main.m diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/Info.plist b/xmake/templates/objc/xcode/iosapp_with_framework/src/framework/Info.plist index 20608314e..20608314e 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/Info.plist +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/framework/Info.plist diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/test.h b/xmake/templates/objc/xcode/iosapp_with_framework/src/framework/test.h index d882546d1..d882546d1 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/test.h +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/framework/test.h diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/test.m b/xmake/templates/objc/xcode/iosapp_with_framework/src/framework/test.m index 71214544b..71214544b 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/src/framework/test.m +++ b/xmake/templates/objc/xcode/iosapp_with_framework/src/framework/test.m diff --git a/xmake/repository/templates/objc/xcode/iosapp_with_framework/xmake.lua b/xmake/templates/objc/xcode/iosapp_with_framework/xmake.lua index e1383b8b2..e1383b8b2 100644 --- a/xmake/repository/templates/objc/xcode/iosapp_with_framework/xmake.lua +++ b/xmake/templates/objc/xcode/iosapp_with_framework/xmake.lua diff --git a/xmake/repository/templates/objc/xcode/macapp/src/AppDelegate.h b/xmake/templates/objc/xcode/macapp/src/AppDelegate.h index 5f5ba059e..5f5ba059e 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/AppDelegate.h +++ b/xmake/templates/objc/xcode/macapp/src/AppDelegate.h diff --git a/xmake/repository/templates/objc/xcode/macapp/src/AppDelegate.m b/xmake/templates/objc/xcode/macapp/src/AppDelegate.m index da967d2ef..da967d2ef 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/AppDelegate.m +++ b/xmake/templates/objc/xcode/macapp/src/AppDelegate.m diff --git a/xmake/repository/templates/objc/xcode/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json b/xmake/templates/objc/xcode/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json index 2db2b1c7c..2db2b1c7c 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/xmake/templates/objc/xcode/macapp/src/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/xmake/repository/templates/objc/xcode/macapp/src/Assets.xcassets/Contents.json b/xmake/templates/objc/xcode/macapp/src/Assets.xcassets/Contents.json index da4a164c9..da4a164c9 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/Assets.xcassets/Contents.json +++ b/xmake/templates/objc/xcode/macapp/src/Assets.xcassets/Contents.json diff --git a/xmake/repository/templates/objc/xcode/macapp/src/Base.lproj/Main.storyboard b/xmake/templates/objc/xcode/macapp/src/Base.lproj/Main.storyboard index 7a6d659a5..7a6d659a5 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/Base.lproj/Main.storyboard +++ b/xmake/templates/objc/xcode/macapp/src/Base.lproj/Main.storyboard diff --git a/xmake/repository/templates/objc/xcode/macapp/src/Info.plist b/xmake/templates/objc/xcode/macapp/src/Info.plist index ce53d780c..ce53d780c 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/Info.plist +++ b/xmake/templates/objc/xcode/macapp/src/Info.plist diff --git a/xmake/repository/templates/objc/xcode/macapp/src/ViewController.h b/xmake/templates/objc/xcode/macapp/src/ViewController.h index a974fc934..a974fc934 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/ViewController.h +++ b/xmake/templates/objc/xcode/macapp/src/ViewController.h diff --git a/xmake/repository/templates/objc/xcode/macapp/src/ViewController.m b/xmake/templates/objc/xcode/macapp/src/ViewController.m index bccdf6189..bccdf6189 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/ViewController.m +++ b/xmake/templates/objc/xcode/macapp/src/ViewController.m diff --git a/xmake/repository/templates/objc/xcode/macapp/src/main.m b/xmake/templates/objc/xcode/macapp/src/main.m index ae3706f51..ae3706f51 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/main.m +++ b/xmake/templates/objc/xcode/macapp/src/main.m diff --git a/xmake/repository/templates/objc/xcode/macapp/src/test.entitlements b/xmake/templates/objc/xcode/macapp/src/test.entitlements index f2ef3ae02..f2ef3ae02 100644 --- a/xmake/repository/templates/objc/xcode/macapp/src/test.entitlements +++ b/xmake/templates/objc/xcode/macapp/src/test.entitlements diff --git a/xmake/repository/templates/objc/xcode/macapp/xmake.lua b/xmake/templates/objc/xcode/macapp/xmake.lua index 1306fce94..1306fce94 100644 --- a/xmake/repository/templates/objc/xcode/macapp/xmake.lua +++ b/xmake/templates/objc/xcode/macapp/xmake.lua diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.h b/xmake/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.h index 5f5ba059e..5f5ba059e 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.h +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.h diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.m b/xmake/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.m index 667420c8c..667420c8c 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.m +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/AppDelegate.m diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json b/xmake/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json index 2db2b1c7c..2db2b1c7c 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/Contents.json b/xmake/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/Contents.json index da4a164c9..da4a164c9 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/Contents.json +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/Assets.xcassets/Contents.json diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Base.lproj/Main.storyboard b/xmake/templates/objc/xcode/macapp_with_framework/src/app/Base.lproj/Main.storyboard index 7a6d659a5..7a6d659a5 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Base.lproj/Main.storyboard +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/Base.lproj/Main.storyboard diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Info.plist b/xmake/templates/objc/xcode/macapp_with_framework/src/app/Info.plist index ce53d780c..ce53d780c 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/Info.plist +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/Info.plist diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/ViewController.h b/xmake/templates/objc/xcode/macapp_with_framework/src/app/ViewController.h index a974fc934..a974fc934 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/ViewController.h +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/ViewController.h diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/ViewController.m b/xmake/templates/objc/xcode/macapp_with_framework/src/app/ViewController.m index bccdf6189..bccdf6189 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/ViewController.m +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/ViewController.m diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/main.m b/xmake/templates/objc/xcode/macapp_with_framework/src/app/main.m index ae3706f51..ae3706f51 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/main.m +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/main.m diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/test.entitlements b/xmake/templates/objc/xcode/macapp_with_framework/src/app/test.entitlements index f2ef3ae02..f2ef3ae02 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/app/test.entitlements +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/app/test.entitlements diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/Info.plist b/xmake/templates/objc/xcode/macapp_with_framework/src/framework/Info.plist index 20608314e..20608314e 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/Info.plist +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/framework/Info.plist diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/test.h b/xmake/templates/objc/xcode/macapp_with_framework/src/framework/test.h index d882546d1..d882546d1 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/test.h +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/framework/test.h diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/test.m b/xmake/templates/objc/xcode/macapp_with_framework/src/framework/test.m index 71214544b..71214544b 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/src/framework/test.m +++ b/xmake/templates/objc/xcode/macapp_with_framework/src/framework/test.m diff --git a/xmake/repository/templates/objc/xcode/macapp_with_framework/xmake.lua b/xmake/templates/objc/xcode/macapp_with_framework/xmake.lua index e1383b8b2..e1383b8b2 100644 --- a/xmake/repository/templates/objc/xcode/macapp_with_framework/xmake.lua +++ b/xmake/templates/objc/xcode/macapp_with_framework/xmake.lua diff --git a/xmake/repository/templates/pascal/console/src/main.pas b/xmake/templates/pascal/console/src/main.pas index a908ffab7..a908ffab7 100644 --- a/xmake/repository/templates/pascal/console/src/main.pas +++ b/xmake/templates/pascal/console/src/main.pas diff --git a/xmake/repository/templates/pascal/console/xmake.lua b/xmake/templates/pascal/console/xmake.lua index 52168c3a4..52168c3a4 100644 --- a/xmake/repository/templates/pascal/console/xmake.lua +++ b/xmake/templates/pascal/console/xmake.lua diff --git a/xmake/repository/templates/pascal/shared/src/foo.pas b/xmake/templates/pascal/shared/src/foo.pas index 788950f46..788950f46 100644 --- a/xmake/repository/templates/pascal/shared/src/foo.pas +++ b/xmake/templates/pascal/shared/src/foo.pas diff --git a/xmake/repository/templates/pascal/shared/src/main.pas b/xmake/templates/pascal/shared/src/main.pas index 02d5e88d0..02d5e88d0 100644 --- a/xmake/repository/templates/pascal/shared/src/main.pas +++ b/xmake/templates/pascal/shared/src/main.pas diff --git a/xmake/repository/templates/pascal/shared/xmake.lua b/xmake/templates/pascal/shared/xmake.lua index fad68bd07..fad68bd07 100644 --- a/xmake/repository/templates/pascal/shared/xmake.lua +++ b/xmake/templates/pascal/shared/xmake.lua diff --git a/xmake/repository/templates/rust/console/src/main.rs b/xmake/templates/rust/console/src/main.rs index 88d5e2749..88d5e2749 100644 --- a/xmake/repository/templates/rust/console/src/main.rs +++ b/xmake/templates/rust/console/src/main.rs diff --git a/xmake/repository/templates/rust/console/xmake.lua b/xmake/templates/rust/console/xmake.lua index 684ea720a..684ea720a 100644 --- a/xmake/repository/templates/rust/console/xmake.lua +++ b/xmake/templates/rust/console/xmake.lua diff --git a/xmake/repository/templates/rust/shared/src/foo.rs b/xmake/templates/rust/shared/src/foo.rs index a3a3aa4a6..a3a3aa4a6 100644 --- a/xmake/repository/templates/rust/shared/src/foo.rs +++ b/xmake/templates/rust/shared/src/foo.rs diff --git a/xmake/repository/templates/rust/shared/src/main.rs b/xmake/templates/rust/shared/src/main.rs index 205d23da3..205d23da3 100644 --- a/xmake/repository/templates/rust/shared/src/main.rs +++ b/xmake/templates/rust/shared/src/main.rs diff --git a/xmake/repository/templates/rust/shared/xmake.lua b/xmake/templates/rust/shared/xmake.lua index 52effc17b..52effc17b 100644 --- a/xmake/repository/templates/rust/shared/xmake.lua +++ b/xmake/templates/rust/shared/xmake.lua diff --git a/xmake/repository/templates/rust/static/src/foo.rs b/xmake/templates/rust/static/src/foo.rs index a3a3aa4a6..a3a3aa4a6 100644 --- a/xmake/repository/templates/rust/static/src/foo.rs +++ b/xmake/templates/rust/static/src/foo.rs diff --git a/xmake/repository/templates/rust/static/src/main.rs b/xmake/templates/rust/static/src/main.rs index 205d23da3..205d23da3 100644 --- a/xmake/repository/templates/rust/static/src/main.rs +++ b/xmake/templates/rust/static/src/main.rs diff --git a/xmake/repository/templates/rust/static/xmake.lua b/xmake/templates/rust/static/xmake.lua index 9eb48bef1..9eb48bef1 100644 --- a/xmake/repository/templates/rust/static/xmake.lua +++ b/xmake/templates/rust/static/xmake.lua diff --git a/xmake/repository/templates/swift/console/src/main.swift b/xmake/templates/swift/console/src/main.swift index ee21045f4..ee21045f4 100644 --- a/xmake/repository/templates/swift/console/src/main.swift +++ b/xmake/templates/swift/console/src/main.swift diff --git a/xmake/repository/templates/swift/console/xmake.lua b/xmake/templates/swift/console/xmake.lua index d07f6547b..d07f6547b 100644 --- a/xmake/repository/templates/swift/console/xmake.lua +++ b/xmake/templates/swift/console/xmake.lua diff --git a/xmake/repository/templates/vala/console/src/main.vala b/xmake/templates/vala/console/src/main.vala index 8e8a32da0..8e8a32da0 100644 --- a/xmake/repository/templates/vala/console/src/main.vala +++ b/xmake/templates/vala/console/src/main.vala diff --git a/xmake/repository/templates/vala/console/xmake.lua b/xmake/templates/vala/console/xmake.lua index 4fb124a8a..4fb124a8a 100644 --- a/xmake/repository/templates/vala/console/xmake.lua +++ b/xmake/templates/vala/console/xmake.lua diff --git a/xmake/repository/templates/vala/shared/src/main.vala b/xmake/templates/vala/shared/src/main.vala index da9fd895e..da9fd895e 100644 --- a/xmake/repository/templates/vala/shared/src/main.vala +++ b/xmake/templates/vala/shared/src/main.vala diff --git a/xmake/repository/templates/vala/shared/src/mymath.vala b/xmake/templates/vala/shared/src/mymath.vala index 4f4e761c5..4f4e761c5 100644 --- a/xmake/repository/templates/vala/shared/src/mymath.vala +++ b/xmake/templates/vala/shared/src/mymath.vala diff --git a/xmake/repository/templates/vala/shared/xmake.lua b/xmake/templates/vala/shared/xmake.lua index 4b4291a78..4b4291a78 100644 --- a/xmake/repository/templates/vala/shared/xmake.lua +++ b/xmake/templates/vala/shared/xmake.lua diff --git a/xmake/repository/templates/vala/static/src/main.vala b/xmake/templates/vala/static/src/main.vala index da9fd895e..da9fd895e 100644 --- a/xmake/repository/templates/vala/static/src/main.vala +++ b/xmake/templates/vala/static/src/main.vala diff --git a/xmake/repository/templates/vala/static/src/mymath.vala b/xmake/templates/vala/static/src/mymath.vala index 4f4e761c5..4f4e761c5 100644 --- a/xmake/repository/templates/vala/static/src/mymath.vala +++ b/xmake/templates/vala/static/src/mymath.vala diff --git a/xmake/repository/templates/vala/static/xmake.lua b/xmake/templates/vala/static/xmake.lua index 8e2430db7..8e2430db7 100644 --- a/xmake/repository/templates/vala/static/xmake.lua +++ b/xmake/templates/vala/static/xmake.lua diff --git a/xmake/repository/templates/zig/console/src/main.zig b/xmake/templates/zig/console/src/main.zig index db34441e1..db34441e1 100644 --- a/xmake/repository/templates/zig/console/src/main.zig +++ b/xmake/templates/zig/console/src/main.zig diff --git a/xmake/repository/templates/zig/console/xmake.lua b/xmake/templates/zig/console/xmake.lua index 28940257d..28940257d 100644 --- a/xmake/repository/templates/zig/console/xmake.lua +++ b/xmake/templates/zig/console/xmake.lua diff --git a/xmake/repository/templates/zig/shared/src/main.zig b/xmake/templates/zig/shared/src/main.zig index 7dc7b2bc4..7dc7b2bc4 100644 --- a/xmake/repository/templates/zig/shared/src/main.zig +++ b/xmake/templates/zig/shared/src/main.zig diff --git a/xmake/repository/templates/zig/shared/src/test.zig b/xmake/templates/zig/shared/src/test.zig index a04ec1544..a04ec1544 100644 --- a/xmake/repository/templates/zig/shared/src/test.zig +++ b/xmake/templates/zig/shared/src/test.zig diff --git a/xmake/repository/templates/zig/shared/xmake.lua b/xmake/templates/zig/shared/xmake.lua index 2577bde9f..2577bde9f 100644 --- a/xmake/repository/templates/zig/shared/xmake.lua +++ b/xmake/templates/zig/shared/xmake.lua diff --git a/xmake/repository/templates/zig/static/src/main.zig b/xmake/templates/zig/static/src/main.zig index 7dc7b2bc4..7dc7b2bc4 100644 --- a/xmake/repository/templates/zig/static/src/main.zig +++ b/xmake/templates/zig/static/src/main.zig diff --git a/xmake/repository/templates/zig/static/src/test.zig b/xmake/templates/zig/static/src/test.zig index a04ec1544..a04ec1544 100644 --- a/xmake/repository/templates/zig/static/src/test.zig +++ b/xmake/templates/zig/static/src/test.zig diff --git a/xmake/repository/templates/zig/static/xmake.lua b/xmake/templates/zig/static/xmake.lua index 2cc6601d2..2cc6601d2 100644 --- a/xmake/repository/templates/zig/static/xmake.lua +++ b/xmake/templates/zig/static/xmake.lua diff --git a/xmake/toolchains/emcc/xmake.lua b/xmake/toolchains/emcc/xmake.lua index 3d64019e6..8313cd226 100644 --- a/xmake/toolchains/emcc/xmake.lua +++ b/xmake/toolchains/emcc/xmake.lua @@ -25,14 +25,25 @@ toolchain("emcc") set_kind("standalone") - local suffix = is_host("windows") and ".bat" or "" - set_toolset("cc", "emcc" .. suffix) - set_toolset("cxx", "emcc" .. suffix, "em++" .. suffix) - set_toolset("ld", "em++" .. suffix, "emcc" .. suffix) - set_toolset("sh", "em++" .. suffix, "emcc" .. suffix) - set_toolset("ar", "emar" .. suffix) - set_toolset("as", "emcc" .. suffix) - set_toolset("ranlib", "emranlib" .. suffix) + local function toolnames(...) + local result = {} + for _, basename in ipairs({...}) do + if is_host("windows") then + table.insert(result, basename .. ".exe") + table.insert(result, basename .. ".bat") + else + table.insert(result, basename) + end + end + return table.unpack(result) + end + set_toolset("cc", toolnames("emcc")) + set_toolset("cxx", toolnames("emcc", "em++")) + set_toolset("ld", toolnames("em++", "emcc")) + set_toolset("sh", toolnames("em++", "emcc")) + set_toolset("ar", toolnames("emar")) + set_toolset("as", toolnames("emcc")) + set_toolset("ranlib", toolnames("emranlib")) on_check(function (toolchain) import("lib.detect.find_tool") @@ -82,4 +93,3 @@ toolchain("emcc") end end end) - diff --git a/xmake/toolchains/mingw/xmake.lua b/xmake/toolchains/mingw/xmake.lua index d0695dcfe..a75ab3cce 100644 --- a/xmake/toolchains/mingw/xmake.lua +++ b/xmake/toolchains/mingw/xmake.lua @@ -22,7 +22,7 @@ toolchain("mingw") set_kind("standalone") set_homepage("http://www.mingw.org/") set_description("Minimalist GNU for Windows") - set_runtimes("stdc++_static", "stdc++_shared") + set_runtimes("stdc++_static", "stdc++_shared", "c++_static", "c++_shared") on_check("check") on_load(function (toolchain) |
