First commit

This commit is contained in:
2024-08-10 14:32:46 +02:00
commit f9fb132a9f
15 changed files with 1124 additions and 0 deletions

20
.gitignore vendored Normal file
View File

@@ -0,0 +1,20 @@
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
.vscode/
*.dll
*.exp
*.pdb
*.ilk
*.obj
*.lib
*.TMP
demo/.godot
publish

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Simon Pribylski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

63
README.md Normal file
View File

@@ -0,0 +1,63 @@
This project is used to compile a GDExtension (godot engine cpp extension), and try to use xmake to manage the project.
It is mainly for learning purpose.
## Install xmake
Install xmake from [here](https://xmake.io/#/guide/installation).
## How to use
You must have godot in your path
First modify the *xmake.lua* to change the project name, and other configurations as needed.
```lua
-- project name, this will be the output shared library name
PROJECT_NAME = "gdexample"
-- project version
VERSION = "0.0.1"
-- where is the godot project saved, default is "demo"
GODOT_PROJECT_FOLDER = "demo"
-- where to save the export project, default is "publish"
PUBLISH_FOLDER = "publish"
```
After change the configurations, you can run the following commands to build, run and export.
```sh
# 1. gen gdextension file (only once)
xmake gengdextension
# 2. build the project
xmake
# 3. open the editor at least once (works only in debug mode)
xmake run Editor
# 4. run the demo (works only in debug mode)
xmake run
# 5. export the project, the executable will be under "publish" folder by default
xmake p
# 6. clean the build and publish
xmake clean
# 7. generate a class that inherits from godot class, like Sprite2D
# by default the generated files will save under "src" folder, you can change it by -d folder/under/src
xmake ext-class -n MySprite2D -b Sprite2D -s myexample1 -d sample
```
For better support in vscode, you can use command "Xmake: UpdateIntellisense" to generate *compile_commands.json*, then update "compileCommands" field in *c_cpp_properties.json* to point to the file.
NOTE: not tested on other platforms execept windows.

410
demo/export_presets.cfg Normal file
View File

@@ -0,0 +1,410 @@
[preset.0]
name="Windows Desktop"
platform="Windows Desktop"
runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
[preset.0.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
binary_format/architecture="x86_64"
codesign/enable=false
codesign/timestamp=true
codesign/timestamp_server_url=""
codesign/digest_algorithm=1
codesign/description=""
codesign/custom_options=PackedStringArray()
application/modify_resources=true
application/icon=""
application/console_wrapper_icon=""
application/icon_interpolation=4
application/file_version=""
application/product_version=""
application/company_name=""
application/product_name=""
application/file_description=""
application/copyright=""
application/trademarks=""
application/export_angle=0
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
$settings = New-ScheduledTaskSettingsSet
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
Start-ScheduledTask -TaskName godot_remote_debug
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"
[preset.1]
name="Linux/X11"
platform="Linux/X11"
runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
[preset.1.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
binary_format/architecture="x86_64"
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="#!/usr/bin/env bash
export DISPLAY=:0
unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
\"{temp_dir}/{exe_name}\" {cmd_args}"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
[preset.2]
name="macOS"
platform="macOS"
runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
[preset.2.options]
export/distribution_type=1
binary_format/architecture="universal"
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
application/icon=""
application/icon_interpolation=4
application/bundle_identifier=""
application/signature=""
application/app_category="Games"
application/short_version=""
application/version=""
application/copyright=""
application/copyright_localized={}
application/min_macos_version="10.12"
application/export_angle=0
display/high_res=true
xcode/platform_build="14C18"
xcode/sdk_version="13.1"
xcode/sdk_build="22C55"
xcode/sdk_name="macosx13.1"
xcode/xcode_version="1420"
xcode/xcode_build="14C18"
codesign/codesign=1
codesign/installer_identity=""
codesign/apple_team_id=""
codesign/identity=""
codesign/entitlements/custom_file=""
codesign/entitlements/allow_jit_code_execution=false
codesign/entitlements/allow_unsigned_executable_memory=false
codesign/entitlements/allow_dyld_environment_variables=false
codesign/entitlements/disable_library_validation=false
codesign/entitlements/audio_input=false
codesign/entitlements/camera=false
codesign/entitlements/location=false
codesign/entitlements/address_book=false
codesign/entitlements/calendars=false
codesign/entitlements/photos_library=false
codesign/entitlements/apple_events=false
codesign/entitlements/debugging=false
codesign/entitlements/app_sandbox/enabled=false
codesign/entitlements/app_sandbox/network_server=false
codesign/entitlements/app_sandbox/network_client=false
codesign/entitlements/app_sandbox/device_usb=false
codesign/entitlements/app_sandbox/device_bluetooth=false
codesign/entitlements/app_sandbox/files_downloads=0
codesign/entitlements/app_sandbox/files_pictures=0
codesign/entitlements/app_sandbox/files_music=0
codesign/entitlements/app_sandbox/files_movies=0
codesign/entitlements/app_sandbox/files_user_selected=0
codesign/entitlements/app_sandbox/helper_executables=[]
codesign/custom_options=PackedStringArray()
notarization/notarization=0
privacy/microphone_usage_description=""
privacy/microphone_usage_description_localized={}
privacy/camera_usage_description=""
privacy/camera_usage_description_localized={}
privacy/location_usage_description=""
privacy/location_usage_description_localized={}
privacy/address_book_usage_description=""
privacy/address_book_usage_description_localized={}
privacy/calendar_usage_description=""
privacy/calendar_usage_description_localized={}
privacy/photos_library_usage_description=""
privacy/photos_library_usage_description_localized={}
privacy/desktop_folder_usage_description=""
privacy/desktop_folder_usage_description_localized={}
privacy/documents_folder_usage_description=""
privacy/documents_folder_usage_description_localized={}
privacy/downloads_folder_usage_description=""
privacy/downloads_folder_usage_description_localized={}
privacy/network_volumes_usage_description=""
privacy/network_volumes_usage_description_localized={}
privacy/removable_volumes_usage_description=""
privacy/removable_volumes_usage_description_localized={}
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="#!/usr/bin/env bash
unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
[preset.3]
name="Android"
platform="Android"
runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
[preset.3.options]
custom_template/debug=""
custom_template/release=""
gradle_build/use_gradle_build=false
gradle_build/export_format=0
gradle_build/min_sdk=""
gradle_build/target_sdk=""
architectures/armeabi-v7a=false
architectures/arm64-v8a=true
architectures/x86=false
architectures/x86_64=false
version/code=1
version/name=""
package/unique_name="com.example.$genname"
package/name=""
package/signed=true
package/app_category=2
package/retain_data_on_uninstall=false
package/exclude_from_recents=false
package/show_in_android_tv=false
package/show_in_app_library=true
package/show_as_launcher_app=false
launcher_icons/main_192x192=""
launcher_icons/adaptive_foreground_432x432=""
launcher_icons/adaptive_background_432x432=""
graphics/opengl_debug=false
xr_features/xr_mode=0
screen/immersive_mode=true
screen/support_small=true
screen/support_normal=true
screen/support_large=true
screen/support_xlarge=true
user_data_backup/allow=false
command_line/extra_args=""
apk_expansion/enable=false
apk_expansion/SALT=""
apk_expansion/public_key=""
permissions/custom_permissions=PackedStringArray()
permissions/access_checkin_properties=false
permissions/access_coarse_location=false
permissions/access_fine_location=false
permissions/access_location_extra_commands=false
permissions/access_mock_location=false
permissions/access_network_state=false
permissions/access_surface_flinger=false
permissions/access_wifi_state=false
permissions/account_manager=false
permissions/add_voicemail=false
permissions/authenticate_accounts=false
permissions/battery_stats=false
permissions/bind_accessibility_service=false
permissions/bind_appwidget=false
permissions/bind_device_admin=false
permissions/bind_input_method=false
permissions/bind_nfc_service=false
permissions/bind_notification_listener_service=false
permissions/bind_print_service=false
permissions/bind_remoteviews=false
permissions/bind_text_service=false
permissions/bind_vpn_service=false
permissions/bind_wallpaper=false
permissions/bluetooth=false
permissions/bluetooth_admin=false
permissions/bluetooth_privileged=false
permissions/brick=false
permissions/broadcast_package_removed=false
permissions/broadcast_sms=false
permissions/broadcast_sticky=false
permissions/broadcast_wap_push=false
permissions/call_phone=false
permissions/call_privileged=false
permissions/camera=false
permissions/capture_audio_output=false
permissions/capture_secure_video_output=false
permissions/capture_video_output=false
permissions/change_component_enabled_state=false
permissions/change_configuration=false
permissions/change_network_state=false
permissions/change_wifi_multicast_state=false
permissions/change_wifi_state=false
permissions/clear_app_cache=false
permissions/clear_app_user_data=false
permissions/control_location_updates=false
permissions/delete_cache_files=false
permissions/delete_packages=false
permissions/device_power=false
permissions/diagnostic=false
permissions/disable_keyguard=false
permissions/dump=false
permissions/expand_status_bar=false
permissions/factory_test=false
permissions/flashlight=false
permissions/force_back=false
permissions/get_accounts=false
permissions/get_package_size=false
permissions/get_tasks=false
permissions/get_top_activity_info=false
permissions/global_search=false
permissions/hardware_test=false
permissions/inject_events=false
permissions/install_location_provider=false
permissions/install_packages=false
permissions/install_shortcut=false
permissions/internal_system_window=false
permissions/internet=false
permissions/kill_background_processes=false
permissions/location_hardware=false
permissions/manage_accounts=false
permissions/manage_app_tokens=false
permissions/manage_documents=false
permissions/manage_external_storage=false
permissions/master_clear=false
permissions/media_content_control=false
permissions/modify_audio_settings=false
permissions/modify_phone_state=false
permissions/mount_format_filesystems=false
permissions/mount_unmount_filesystems=false
permissions/nfc=false
permissions/persistent_activity=false
permissions/post_notifications=false
permissions/process_outgoing_calls=false
permissions/read_calendar=false
permissions/read_call_log=false
permissions/read_contacts=false
permissions/read_external_storage=false
permissions/read_frame_buffer=false
permissions/read_history_bookmarks=false
permissions/read_input_state=false
permissions/read_logs=false
permissions/read_phone_state=false
permissions/read_profile=false
permissions/read_sms=false
permissions/read_social_stream=false
permissions/read_sync_settings=false
permissions/read_sync_stats=false
permissions/read_user_dictionary=false
permissions/reboot=false
permissions/receive_boot_completed=false
permissions/receive_mms=false
permissions/receive_sms=false
permissions/receive_wap_push=false
permissions/record_audio=false
permissions/reorder_tasks=false
permissions/restart_packages=false
permissions/send_respond_via_message=false
permissions/send_sms=false
permissions/set_activity_watcher=false
permissions/set_alarm=false
permissions/set_always_finish=false
permissions/set_animation_scale=false
permissions/set_debug_app=false
permissions/set_orientation=false
permissions/set_pointer_speed=false
permissions/set_preferred_applications=false
permissions/set_process_limit=false
permissions/set_time=false
permissions/set_time_zone=false
permissions/set_wallpaper=false
permissions/set_wallpaper_hints=false
permissions/signal_persistent_processes=false
permissions/status_bar=false
permissions/subscribed_feeds_read=false
permissions/subscribed_feeds_write=false
permissions/system_alert_window=false
permissions/transmit_ir=false
permissions/uninstall_shortcut=false
permissions/update_device_stats=false
permissions/use_credentials=false
permissions/use_sip=false
permissions/vibrate=false
permissions/wake_lock=false
permissions/write_apn_settings=false
permissions/write_calendar=false
permissions/write_call_log=false
permissions/write_contacts=false
permissions/write_external_storage=false
permissions/write_gservices=false
permissions/write_history_bookmarks=false
permissions/write_profile=false
permissions/write_secure_settings=false
permissions/write_settings=false
permissions/write_sms=false
permissions/write_social_stream=false
permissions/write_sync_settings=false
permissions/write_user_dictionary=false

1
demo/icon.svg Normal file
View File

@@ -0,0 +1 @@
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>

After

Width:  |  Height:  |  Size: 949 B

37
demo/icon.svg.import Normal file
View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cuend5rtkhbnp"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

10
demo/main.tscn Normal file
View File

@@ -0,0 +1,10 @@
[gd_scene load_steps=2 format=3 uid="uid://uiwigxsdnci1"]
[ext_resource type="Texture2D" uid="uid://cuend5rtkhbnp" path="res://icon.svg" id="1_q81dj"]
[node name="Node2D" type="Node2D"]
[node name="GDExample" type="GDExample" parent="."]
position = Vector2(5.20978, 6.34048)
texture = ExtResource("1_q81dj")
centered = false

16
demo/project.godot Normal file
View File

@@ -0,0 +1,16 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="demo"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.2", "Forward Plus")
config/icon="res://icon.svg"

315
godot.lua Normal file
View File

@@ -0,0 +1,315 @@
------- project settings -------
-- project name
set_project(PROJECT_NAME)
-- project version
set_version(VERSION)
-- min version of xmake we need to run
-- NOTE: this is the version i used to develop this template, may not 100% correct
set_xmakever("2.9.0")
add_rules("mode.debug", "mode.release")
-- c++17 is required for godot 4.x, we use c++20 here
set_languages("c++20")
-- use latest 4.x version by default
add_requires("godotcpp4")
------- custom tasks -------
-- NOTE:
-- xmake cannot accept the global variables in on_xxx functions, so we use a wrapper function to bind it
-- export specified godot project, with the export execution name
-- args:
-- target_platform: the target platform, like "Windows Desktop"
-- name: the export execute name, it will be endswith ".exe" on windows
task("export")
on_run((function(godot_project_folder, publish_folder)
return function(target_platform)
local name = godot_project_folder
-- different platform may have different execute name
-- xmake supported platforms:
-- windows
-- cross
-- linux
-- macosx
-- android
-- iphoneos
-- watchos
if is_plat("windows") then
name = name .. ".exe"
end
local export_mode = "export-debug"
if is_mode("release") then
export_mode = "export-release"
end
if not os.isdir(publish_folder) then
os.mkdir(publish_folder)
end
local godot_project_file = path.join(godot_project_folder, "project.godot")
local export_path = path.absolute(path.join(publish_folder, name))
os.execv("echo", {"godot", godot_project_file, export_mode, target_platform, export_path})
os.exec("godot %s --headless --%s %s %s", godot_project_file, export_mode, "\"" .. target_platform .. "\"", export_path)
end
end)(GODOT_PROJECT_FOLDER, PUBLISH_FOLDER))
task_end()
-- clean the publish folder and build folder
task("clean-publish")
on_run((function(godot_project_folder, publish_folder)
return function ()
-- remove publish folder
if os.isdir(publish_folder) then
os.tryrm(publish_folder)
end
-- remove build target folder
local bin_dir = path.join(godot_project_folder, "bin")
if os.isdir(bin_dir) then
os.tryrm(path.join(bin_dir, "$(os)"))
end
end
end)(GODOT_PROJECT_FOLDER, PUBLISH_FOLDER))
task_end()
-- tasks that exposed to cli
-- NOTE: for complex tasks, we can use a seprate file to define it
-- generate a class that inherit from godot class
-- args:
-- name: the new class name
-- basename: the base class name to inherit (must under godot_cpp/classes)
-- dir: the directory to save the class (must under src)
-- namespace: the namespace of the new class
task("ext-class")
on_run(function ()
-- more on: https://xmake.io/#/manual/plugin_task
-- we need this module to load options from menu
import "core.base.option"
local namespace = option.get("namespace")
local name = option.get("name")
local base = option.get("base")
local dir = option.get("dir")
-- we calculate these here, in case there is any special case to handle
local header_guard = string.upper(name) .. "_H"
import("class_tpl", {rootdir="templates", alias="class_render"})
-- header and impl text
local header_text = class_render.render_header(header_guard, namespace, name, base)
local impl_text = class_render.render_impl(namespace, name)
-- save
local output_dir = "src"
if dir ~= nil then
output_dir = path.join("src", dir)
end
if not os.isdir(output_dir) then
os.mkdir(output_dir)
end
local header_file = path.join(output_dir, string.lower(name) .. ".h")
local impl_file = path.join(output_dir, string.lower(name) .. ".cpp")
io.writefile(header_file, header_text)
io.writefile(impl_file, impl_text)
end)
-- options
set_menu {
usage = "xmake ext-class [options]",
description = "Generate godot class that inherits from a base class under godot_cpp/classes",
options = {
-- kv options
-- (short, long), (kv, default_value), description, [values])
{"s", "namespace", "kv", "godot", "Set the namespace of the new class"},
{"d", "dir", "kv", nil, "Set the directory to save the class"},
{},
-- single value options
{"n", "name", "v", nil, "Set the new class name"},
{"b", "base", "v", nil, "Set the base class name to inherit"},
}
}
task_end()
task("gengdextension")
on_run((function(godot_project_folder, project_name)
return function ()
local bin_dir = path.join(godot_project_folder, "bin")
if not os.isdir(bin_dir) then
os.mkdir(bin_dir)
end
local godot_gdextension_file = path.join(bin_dir, project_name .. ".gdextension")
local fileContent =
[[
[icons]
ProjectName = "res://icon.svg"
[configuration]
entry_symbol = "library_init"
compatibility_minimum = "4.2"
[libraries]
macos.debug = "res://lib/libProjectName.macos_framework"
macos.release = "res://lib/libProjectName.macos_framework"
window.debug.x86_32 = "res://lib/libProjectName.windows_debug_x86.dll"
window.release.x86_32 = "res://lib/libProjectName.windows_release_x86.dll"
window.debug.x86_64 = "res://lib/libProjectName.windows_debug_x64.dll"
window.release.x86_64 = "res://lib/libProjectName.windows_release_x64.dll"
linux.debug.x86_64 = "res://lib/libProjectName.linux_debug_x86_64.so"
linux.release.x86_64 = "res://lib/libProjectName.linux_release_x86_64.so"
linux.debug.arm64 = "res://lib/libProjectName.linux_debug_arm64.so"
linux.release.arm64 = "res://lib/libProjectName.linux_release_arm64.so"
linux.debug.rv64 = "res://lib/libProjectName.linux_debug_rv64.so"
linux.release.rv64 = "res://lib/libProjectName.linux_release_rv64.so"
android.debug.x86_64 = "res://lib/libProjectName.android_debug_x86_64.so"
android.release.x86_64 = "res://lib/libProjectName.android_release_x86_64.so"
android.debug.arm64 = "res://lib/libProjectName.android_debug_arm64.so"
android.release.arm64 = "res://lib/libProjectName.android_release_arm64.so"
]]
-- needs testing with macos
fileContent = string.gsub(fileContent, "ProjectName", project_name)
io.writefile(godot_gdextension_file, fileContent)
end
end)(GODOT_PROJECT_FOLDER, PROJECT_NAME))
-- options
set_menu {
usage = "xmake gengdextension",
description = "Generate gdextension file",
}
task_end()
------- output settings -------
-- more on https://xmake.io/#/manual/project_target
target(PROJECT_NAME)
set_kind("shared")
set_default(true)
add_packages("godotcpp4")
-- more on https://xmake.io/#/manual/project_target?id=targetadd_files
add_files("src/*.cpp")
-- change the output name
set_basename(PROJECT_NAME .. ".$(os)_$(mode)_$(arch)")
-- libraries will saved in os level folder
set_targetdir(GODOT_PROJECT_FOLDER .. "/lib")
-- where to save .obj files
-- we use a seprate folder, so that it will not populate the targer folder
set_objectdir("build/.objs")
-- where .d files are saved
set_dependir("build/.deps")
-- set_optimize("smallest")
-- handlers
-- before_run(function (target) end)
-- after_run(function (target) end)
-- before_build(function (target) end)
-- after_build(function (target) end)
-- before_clean(function (target) end)
-- after_clean(function (target) end)
on_run(
(function(godot_project_folder)
return function(target)
os.execv("echo", {"godot --path", godot_project_folder})
os.exec("godot --path " .. godot_project_folder)
end
end)(GODOT_PROJECT_FOLDER)
)
on_package(function(target)
import("core.base.task")
target_platform = "Unknown"
if is_plat("windows") then
target_platform = "Windows Desktop"
elseif is_plat("macosx") then
target_platform = "macOS"
elseif is_plat("linux") then
target_platform = "Linux/X11"
elseif is_plat("android") then
target_platform = "Android"
end
task.run("export", {}, target_platform)
end)
after_clean(function (target)
import("core.base.task")
task.run("clean-publish")
end)
target("Editor")
set_default(false)
-- Disable building
on_build((function() end))
on_run(
(function(godot_project_folder)
return function(target)
local project_file = path.join(godot_project_folder, "project.godot")
os.execv("echo", {"godot", project_file})
os.exec("godot " .. project_file)
end
end)(GODOT_PROJECT_FOLDER)
)

28
src/gdexample.cpp Normal file
View File

@@ -0,0 +1,28 @@
#include "gdexample.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void GDExample::_bind_methods() {
// ClassDB::bind_method(D_METHOD("_process", "delta"), &GDExample::_process);
}
GDExample::GDExample()
{
time_passed = 0.0;
}
GDExample::~GDExample() {}
void GDExample::_process(float delta)
{
time_passed += delta;
auto new_position = Vector2(
10.0 + (10.0 * sin(time_passed * 2.0)),
10.0 + (10.0 * cos(time_passed * 1.5)));
set_position(new_position);
}

24
src/gdexample.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef GDEXAMPLE_H
#define GDEXAMPLE_H
#include <godot_cpp/classes/sprite2d.hpp>
namespace godot
{
class GDExample : public Sprite2D
{
GDCLASS(GDExample, Sprite2D)
private:
double time_passed;
protected:
static void _bind_methods();
public:
GDExample();
~GDExample();
void _process(float delta);
};
}
#endif

44
src/register_types.cpp Normal file
View File

@@ -0,0 +1,44 @@
#include "register_types.h"
#include "gdexample.h"
#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>
using namespace godot;
void initialize_example_module(ModuleInitializationLevel p_level)
{
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE)
{
return;
}
ClassDB::register_class<GDExample>();
}
void uninitialize_example_module(ModuleInitializationLevel p_level)
{
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE)
{
return;
}
}
extern "C"
{
GDExtensionBool GDE_EXPORT library_init(
GDExtensionInterfaceGetProcAddress p_get_proc,
const GDExtensionClassLibraryPtr p_library,
GDExtensionInitialization *r_initialization)
{
godot::GDExtensionBinding::InitObject init_obj(p_get_proc, p_library, r_initialization);
init_obj.register_initializer(initialize_example_module);
init_obj.register_terminator(uninitialize_example_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}

11
src/register_types.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef GDEXAMPLE_REGISTER_TYPES_H
#define GDEXAMPLE_REGISTER_TYPES_H
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void initialize_example_module(ModuleInitializationLevel p_level);
void uninitialize_example_module(ModuleInitializationLevel p_level);
#endif

103
templates/class_tpl.lua Normal file
View File

@@ -0,0 +1,103 @@
--[[
#ifndef $(HEADER_GUARD)
#define $(HEADER_GUARD)
#include <godot_cpp/classes/$(BASECLASS_HEADER_NAME).hpp>
namespace $(NAMESPACE)
{
class $(CLASS_NAME) : public godot::$(BASE_CLASS)
{
GDCLASS($(CLASS_NAME), godot::$(BASE_CLASS)
protected:
static void _bind_methods();
public:
$(CLASS_NAME)();
~$(CLASS_NAME)();
void _process(float delta);
};
}
#endif
]]
function render_header(header_guard, namespace, class_name, base_class)
local template = {
string.format("#ifndef %s", header_guard),
string.format("#define %s", header_guard),
string.format("#include <godot_cpp/classes/%s.hpp>", string.lower(base_class)),
string.format("namespace %s", namespace),
"{",
string.format(" class %s : public godot::%s", class_name, base_class),
" {",
string.format(" GDCLASS(%s, godot::%s)", class_name, base_class),
" protected:",
string.format(" static void _bind_methods();"),
string.format(" public:"),
string.format(" %s();", class_name),
string.format(" ~%s();", class_name),
string.format(" void _process(float delta);"),
" };",
"}",
"#endif",
}
return table.concat(template, "\n")
end
--[[
#include "{% echo(" " .. string.lower(ClassName)) %}.h"
using namespace {*Namespace*};
void {*ClassName*}::_bind_methods() {
// bind your own methods here, like
// ClassDB::bind_method(D_METHOD("my_foo", "delta"), &{ClassName}::my_foo);
}
{*ClassName*}::{*ClassName*}()
{
// initialize here
}
{*ClassName*}::~{*ClassName*}() {}
void {*ClassName*}::_process(float delta)
{
// do update here
}
]]
function render_impl(namespace, classname)
local template = {
string.format("#include \"%s.h\"", string.lower(classname)),
string.format("using namespace %s;", namespace),
"",
string.format("void %s::_bind_methods()", classname),
"{",
" // bind your own methods here, like",
string.format(" // ClassDB::bind_method(D_METHOD(\"my_foo\", \"delta\"), &%s::my_foo);", classname),
"}",
"",
string.format("%s::%s()", classname, classname),
"{",
" // initialize here",
"}",
"",
string.format("%s::~%s()", classname, classname),
"{",
" // do clean up here",
"}",
"",
string.format("void %s::_process(float delta)", classname),
"{",
" // do update here",
"}"
}
return table.concat(template, "\n")
end

21
xmake.lua Normal file
View File

@@ -0,0 +1,21 @@
-- TODO:
-- 1. support other platforms
-- 2. switch optimization level
-- 3. refine the run command, as it currently run the project by default, maybe start a demo scene or a specified scene?
------- basic custom config part -------
-- project name
PROJECT_NAME = "gdexample"
-- project version
VERSION = "0.0.1"
-- godot project folder, this will be used as export name, so be careful to make sure it is a valid name
GODOT_PROJECT_FOLDER = "demo"
-- publish folder, the exported files will be put here
PUBLISH_FOLDER = "publish"
includes("godot.lua")