Skip to content

Commit d7fb2d1

Browse files
author
Vano
committed
TEMP src -> header_dir rename, SCons env -> dict env, TODO optional advanced includes,
1 parent 8f9a543 commit d7fb2d1

File tree

7 files changed

+155
-102
lines changed

7 files changed

+155
-102
lines changed

CMakeLists.txt

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,92 @@
11
# TEMPORARILY works only on top of my godot-cpp Cmake rewrite
2-
cmake_minimum_required(VERSION 3.24)
2+
cmake_minimum_required(VERSION 3.6)
33
project(scripts)
44

5-
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
6-
include(godot-cppscript)
7-
85
add_subdirectory(godot-cpp)
96

107
# Get Sources
11-
file(GLOB_RECURSE SOURCES ../src/*.c**)
12-
13-
###############################
14-
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src)
15-
set(GEN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../.gen)
16-
set(GEN_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/../src/scripts.gen.h)
17-
18-
file(GLOB_RECURSE CPPSCRIPT_HEADERS ../src/*.hpp)
19-
20-
create_cppscript_target(
21-
cppscript.h
22-
${CMAKE_CURRENT_SOURCE_DIR}
23-
${INCLUDE_DIR}
24-
${GEN_DIR}
25-
${GEN_HEADER}
26-
ON
27-
CPPSCRIPT_MY_SOURCES
28-
)
8+
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS ../src/*.c**)
9+
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS ../src/*.h**)
2910

30-
###############################
3111
# Define our godot-cpp library
32-
message("MY_SOURCES=${CPPSCRIPT_MY_SOURCES}")
33-
add_library(${PROJECT_NAME} SHARED
34-
${SOURCES}
35-
${CPPSCRIPT_MY_SOURCES}
36-
${GEN_HEADER}
37-
${CPPSCRIPT_HEADERS}
38-
src/register_types.cpp
39-
)
12+
if(${PLATFORM} STREQUAL "WEB")
13+
# wasm libraries loaded with dlopen() are created like this in cmake
14+
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
15+
set_target_properties(${PROJECT_NAME}
16+
PROPERTIES
17+
PREFIX "lib"
18+
SUFFIX ".wasm"
19+
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/project/bin"
20+
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/project/bin"
21+
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/project/bin"
22+
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/project/bin"
23+
24+
)
25+
elseif(${PLATFORM} STREQUAL "MACOS")
26+
# TODO: create framework with cmake FRAMEWORK property
27+
# or with template file
28+
message(WARNING "Mac/IOS framework configuration is not tested and may not work.")
4029

41-
#add_dependencies(${PROJECT_NAME} cppscript-target)
42-
target_include_directories(${PROJECT_NAME} PRIVATE ../src src/)
30+
add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS})
31+
set_target_properties(${PROJECT_NAME} PROPERTIES
32+
FRAMEWORK TRUE
33+
MACOSX_FRAMEWORK_IDENTIFIER com.godotengine.${PROJECT_NAME}
34+
MACOSX_FRAMEWORK_INFO_PLIST Info.plist
35+
)
36+
else()
37+
add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS})
38+
endif()
4339

4440
target_link_libraries(${PROJECT_NAME} PUBLIC godot-cpp)
4541

46-
get_directory_property(GODOT_C_FLAGS DIRECTORY godot-cpp DEFINITION GODOT_C_FLAGS)
42+
get_directory_property(GODOT_CC_FLAGS DIRECTORY godot-cpp DEFINITION GODOT_CC_FLAGS)
4743
get_directory_property(GODOT_CXX_FLAGS DIRECTORY godot-cpp DEFINITION GODOT_CXX_FLAGS)
4844
target_compile_options(${PROJECT_NAME} PRIVATE
49-
${GODOT_C_FLAGS}
45+
${GODOT_CC_FLAGS}
5046
${GODOT_CXX_FLAGS}
5147
)
5248

5349
get_directory_property(GODOT_LINK_FLAGS DIRECTORY godot-cpp DEFINITION GODOT_LINK_FLAGS)
54-
target_link_options(${PROJECT_NAME} PRIVATE ${GODOT_LINK_FLAGS}) # -Wl,--as-needed -nostdlib++)
50+
target_link_options(${PROJECT_NAME} PRIVATE ${GODOT_LINK_FLAGS})
5551

5652

5753
get_directory_property(LIBRARY_SUFFIX DIRECTORY godot-cpp DEFINITION LIBRARY_SUFFIX)
5854
set_target_properties(${PROJECT_NAME}
5955
PROPERTIES
60-
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin"
6156
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin"
62-
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin"
63-
57+
LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../bin"
58+
LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../bin"
59+
LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../bin"
60+
LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../bin"
61+
6462
OUTPUT_NAME "${PROJECT_NAME}${LIBRARY_SUFFIX}"
6563
)
64+
if(${GODOT_CPP_WARNING_AS_ERROR})
65+
set_warning_as_error(${PROJECT_NAME})
66+
endif()
67+
68+
###############################
69+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
70+
include(godot-cppscript)
71+
72+
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src)
73+
set(GEN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../.gen)
74+
75+
file(GLOB_RECURSE CPPSCRIPT_HEADERS ../src/*.hpp)
76+
77+
get_target_property(DEFS ${PROJECT_NAME} COMPILE_DEFINITIONS)
78+
get_target_property(INC_PATHS ${PROJECT_NAME} INCLUDE_DIRECTORIES)
79+
create_cppscript_target(
80+
cppscript.h
81+
${INCLUDE_DIR}
82+
${GEN_DIR}
83+
ON
84+
"${INC_PATHS}"
85+
"${DEFS}"
86+
CPPSCRIPT_MY_SOURCES
87+
)
88+
89+
target_sources(${PROJECT_NAME} PRIVATE ${CPPSCRIPT_MY_SOURCES})
90+
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR} src)
91+
###############################
6692

SConstruct

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@ library_name = 'scripts'
66

77
env = SConscript('godot-cpp/SConstruct').Clone()
88

9-
sources = GlobRecursive(SRC_DIR, '*.cpp') + [env.File('src/register_types.cpp')]
9+
sources = GlobRecursive(SRC_DIR, '*.cpp')
1010
scripts = GlobRecursive(SRC_DIR, '*.hpp')
1111

1212
env.Append(CPPPATH=[SRC_DIR, 'src'])
1313
# CppScript config
1414
env['header_name'] = 'cppscript.h' # Name of header to be included to enable cppscript
1515
# (Prefer name unique to your project)
16-
env['src'] = SRC_DIR # Path to C++ source files
16+
env['header_dir'] = SRC_DIR # Path to C++ header files
1717
env['gen_dir'] = "../.gen" # Path for generated object files
18-
env['gen_header'] = os.path.join(SRC_DIR, 'scripts.gen.h') # Path to generated header
1918
env['auto_methods'] = True # Generate bindings to public methods automatically
2019
# Or require GMETHOD() before methods
20+
env.Append(CXXFLAGS='-fdiagnostics-color=always')
2121
env.Append(BUILDERS={'CppScript' : Builder(
2222
action=generate_header_scons,
2323
emitter=generate_header_emitter)})

cmake/godot-cppscript.cmake

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
find_package(Python3 3.4 REQUIRED)
22

3+
set(CPPSCRIPT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
4+
35
#TODO: make it work in parallel
4-
function(create_cppscript_target HEADER_NAME GODOT_CPPSCRIPT_DIR HEADERS_DIR GEN_DIR GEN_HEADER AUTO_METHODS CPPSCRIPT_SOURCES)
6+
function(create_cppscript_target HEADER_NAME HEADERS_DIR GEN_DIR AUTO_METHODS INCLUDE_PATHS COMPILE_DEFS CPPSCRIPT_SOURCES)
7+
if("${COMPILE_DEFS}" STREQUAL "DEFS-NOTFOUND")
8+
set(COMPILE_DEFS "")
9+
endif()
510
if(${AUTO_METHODS})
611
set(AUTO_METHODS_STR "True")
712
else()
@@ -16,25 +21,28 @@ function(create_cppscript_target HEADER_NAME GODOT_CPPSCRIPT_DIR HEADERS_DIR GEN
1621
endforeach()
1722
set(${CPPSCRIPT_SOURCES} ${SOURCES_LIST} PARENT_SCOPE)
1823

19-
add_custom_command(OUTPUT ${GEN_HEADER} ${SOURCES_LIST}
20-
COMMAND ${Python3_EXECUTABLE} "${GODOT_CPPSCRIPT_DIR}/cppscript_bindings.py"
21-
"--header-name" "${HEADER_NAME}"
22-
"--src" "${HEADERS_DIR}"
23-
"--gen-dir" "${GEN_DIR}"
24-
"--gen-header" "${GEN_HEADER}"
25-
"--auto-methods" "${AUTO_METHODS_STR}"
26-
${CPPSCRIPT_HEADERS}
24+
add_custom_command(
25+
OUTPUT
26+
${HEADERS_DIR}/${HEADER_NAME}
27+
${HEADERS_DIR}/scripts.gen.h
28+
${HEADERS_DIR}/properties.gen.h
29+
${SOURCES_LIST}
30+
31+
COMMAND
32+
${Python3_EXECUTABLE} "${CPPSCRIPT_DIR}/cppscript_bindings.py"
33+
"--header-name" "${HEADER_NAME}"
34+
"--header-dir" "${HEADERS_DIR}"
35+
"--gen-dir" "${GEN_DIR}"
36+
"--auto-methods" "${AUTO_METHODS_STR}"
37+
"--definitions" ${COMPILE_DEFS}
38+
"--include-paths" ${CPPSCRIPT_DIR}/src ${HEADERS_DIR} ${INCLUDE_PATHS}
39+
"--"
40+
${CPPSCRIPT_HEADERS}
2741

2842
DEPENDS ${CPPSCRIPT_HEADERS}
29-
WORKING_DIRECTORY ${GODOT_CPPSCRIPT_DIR}
43+
WORKING_DIRECTORY ${CPPSCRIPT_DIR}
3044
VERBATIM
3145
COMMENT "Parsing header files..."
3246
)
33-
34-
#add_custom_target(${TARGET_NAME} DEPENDS ${GEN_HEADER} ${SOURCES_LIST})
35-
#foreach(file ${SOURCES_LIST})
36-
# file(WRITE ${file} "")
37-
# endforeach()
38-
file(REMOVE ${GEN_DIR}/defs.json)
3947
endfunction()
4048

cppscript.py

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ def GlobRecursive(path, pattern, **kwargs):
1717
KEYWORDS = ['GPROPERTY', 'GMETHOD', 'GGROUP', 'GSUBGROUP', 'GBITFIELD', 'GSIGNAL', 'GRPC', 'GVARARG', 'GIGNORE']
1818
INIT_LEVELS = ['GINIT_LEVEL_CORE', 'GINIT_LEVEL_SERVERS', 'GINIT_LEVEL_SCENE', 'GINIT_LEVEL_EDITOR']
1919

20-
CPPSCRIPT_BODY="""#ifndef {0}
20+
DONOTEDIT_MSG = "/*-- GENERATED FILE - DO NOT EDIT --*/\n\n"
21+
22+
CPPSCRIPT_BODY= DONOTEDIT_MSG + """#ifndef {0}
2123
#define {0}
2224
#include <cppscript_defs.h>
2325
#include "properties.gen.h"
@@ -39,7 +41,7 @@ class CppScriptException(Exception):
3941
pass
4042

4143
def filename_to_gen_filename(name, env):
42-
return os.path.join(env['gen_dir'], os.path.relpath(name.replace('.hpp', '.gen.cpp'), env['src']))
44+
return os.path.join(env['gen_dir'], os.path.relpath(name.replace('.hpp', '.gen.cpp'), env['header_dir']))
4345

4446

4547
def collapse_list(list, key, action):
@@ -149,31 +151,58 @@ def is_virtual_method(cursor):
149151

150152
# Builder
151153
def generate_header_emitter(target, source, env):
152-
return [env.File(env['gen_header'])] + [env.File(filename_to_gen_filename(str(i), env)) for i in source], source
154+
return [env.File(os.path.join(env['header_dir'], 'scripts.gen.h'))] + [env.File(filename_to_gen_filename(str(i), env)) for i in source], source
153155

154156

155157
def generate_header_scons(target, source, env):
156-
return generate_header(target, source, env, get_file_scons)
158+
# Convert scons variables to cppscript's env
159+
cppscript_env = {
160+
'header_name' : env['header_name'],
161+
'header_dir' : env['header_dir'],
162+
'gen_dir' : env['gen_dir'],
163+
'compile_defs' : [f'{i[0]}={i[1]}' if type(i) is tuple else str(i) for i in env['CPPDEFINES']],
164+
'include_paths' : env['CPPPATH'],
165+
'auto_methods' : env['auto_methods']
166+
}
167+
157168

169+
return generate_header(target, source, cppscript_env, get_file_scons)
158170

159-
def generate_header_cmake(target, source, env):
160-
return generate_header(target, source, env, get_file_cmake)
171+
172+
def generate_header_cmake(source, env):
173+
return generate_header(None, source, env, get_file_cmake)
161174

162175

163176
def generate_header(target, source, env, get_file):
164177
index = Index.create()
165-
prop_file_name = os.path.join(env['src'], 'properties.gen.h')
178+
prop_file_name = os.path.join(env['header_dir'], 'properties.gen.h')
179+
180+
# Move properties file if exists to avoid infinite cycle for auto-genereted getter/setters:
181+
# no method definition -> generate one -> parse |
182+
# ^ V
183+
# | do NOT generate one <- method exists
166184
try:
167185
shutil.move(prop_file_name, prop_file_name + '.tmp')
168186
except:
169187
pass
170188

189+
# Create include header if not exists
190+
path = os.path.join(env['header_dir'], env['header_name'])
191+
if not os.path.exists(path):
192+
with open(path, 'w') as file:
193+
file.write(CPPSCRIPT_BODY.format(env['header_name'].replace(' ', '_').replace('.', '_').upper()))
194+
171195
try:
172196
defs_file_path = os.path.join(env['gen_dir'], 'defs.json')
173197
cached_defs_all = load_defs_json(defs_file_path)
174198
cached_defs = cached_defs_all.get('files', {})
175199
need_regen = False
176200

201+
# Prepare parser args
202+
env['parser_args'] = [f'-I{i}' for i in env['include_paths']] + \
203+
[f'-D{i}' for i in env['compile_defs']] + \
204+
[f'-DGDCLASS']
205+
177206
new_defs_files = {}
178207
for s in source:
179208
filename, file_content = get_file(s)
@@ -186,12 +215,6 @@ def generate_header(target, source, env, get_file):
186215

187216
new_defs_all = {'hash' : cached_defs_all.get('hash', None), 'files' : new_defs_files}
188217

189-
# Create include header if not exists
190-
path = os.path.join(env['src'], env['header_name'])
191-
if not os.path.exists(path):
192-
with open(path, 'w') as file:
193-
file.write(CPPSCRIPT_BODY.format(env['header_name'].replace(' ', '_').replace('.', '_').upper()))
194-
195218
if write_register_header(new_defs_all, env) or need_regen:
196219
write_property_header(new_defs_all, env)
197220
try:
@@ -213,8 +236,8 @@ def generate_header(target, source, env, get_file):
213236

214237
return 0
215238

216-
def parse_header(index, filename, filecontent, src, auto_methods):
217-
translation_unit = index.parse(filename, args=[f'-I{src}', '-Isrc', '-DGDCLASS'], unsaved_files=[(filename, filecontent)], options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD)
239+
def parse_header(index, filename, filecontent, env):
240+
translation_unit = index.parse(filename, args=env['parser_args'], unsaved_files=[(filename, filecontent)], options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD)
218241

219242
if not translation_unit:
220243
raise CppScriptException("{filename}: failed to create translation unit")
@@ -433,7 +456,7 @@ def apply_macros(item, macros):
433456
case CursorKind.CXX_METHOD:
434457
is_virtual = is_virtual_method(item)
435458
properties = {}
436-
if process_macros(item, macros, properties, (is_virtual and item.spelling.startswith('_')) or not auto_methods):
459+
if process_macros(item, macros, properties, (is_virtual and item.spelling.startswith('_')) or not env['auto_methods']):
437460
properties |= { 'name' : item.spelling,
438461
'bind_name' : item.spelling,
439462
'return' : item.result_type.spelling,
@@ -481,14 +504,13 @@ def apply_macros(item, macros):
481504

482505

483506
def parse_and_write_header(index, filename, filecontent, env):
484-
defs = parse_header(index, filename, filecontent, env['src'], env['auto_methods'])
507+
defs = parse_header(index, filename, filecontent, env)
485508
write_header(filename, defs, env)
486509

487510
return defs
488511

489512

490513
def write_header(file, defs, env):
491-
src = env['src']
492514
header_defs = []
493515
for class_name_full, content in defs.items():
494516
class_name = content['class_name']
@@ -584,29 +606,28 @@ def write_header(file, defs, env):
584606
([property_set_get_defs] if property_set_get_defs != '' else []) + \
585607
([outside_bind] if outside_bind != '' else [])
586608

587-
file_name = filename_to_gen_filename(file, env)
609+
gen_filename = filename_to_gen_filename(file, env)
588610
content = ''
589611
if len(defs) != 0:
590-
header_include = '#include <cppscript_bindings.h>\n\n#include <{}>\n\nusing namespace godot;\n\n'.format(os.path.relpath(file, src).replace('\\', '/'))
591-
content = header_include + '\n'.join(header_defs)
612+
header_include = '#include <cppscript_bindings.h>\n\n#include "{}"\n\nusing namespace godot;\n\n'.format(os.path.relpath(file, os.path.dirname(gen_filename)).replace('\\', '/'))
613+
content = DONOTEDIT_MSG + header_include + '\n'.join(header_defs)
592614

593-
os.makedirs(os.path.dirname(file_name), exist_ok=True)
594-
with open(file_name, 'w') as fileopen:
615+
os.makedirs(os.path.dirname(gen_filename), exist_ok=True)
616+
with open(gen_filename, 'w') as fileopen:
595617
fileopen.write(content)
596618

597619

598620
def write_register_header(defs_all, env):
599-
src = env['src']
600-
target = env['gen_header']
601-
scripts_header = ''
621+
target = os.path.join(env['header_dir'], 'scripts.gen.h')
622+
scripts_header = DONOTEDIT_MSG
602623
classes_register_levels = {name[12:] : [] for name in INIT_LEVELS}
603624

604625
for file, filecontent in defs_all['files'].items():
605626
classes = filecontent['content']
606627
if len(classes) == 0:
607628
continue
608629

609-
scripts_header += '#include <{}>\n'.format(os.path.relpath(file, src).replace('\\', '/'))
630+
scripts_header += '#include "{}"\n'.format(os.path.relpath(file, os.path.dirname(target)).replace('\\', '/'))
610631
for class_name_full, content in classes.items():
611632
# Ensure parent classes are registered before children
612633
# by iterating throught pairs of (base_name, register_str)
@@ -644,8 +665,8 @@ def write_register_header(defs_all, env):
644665

645666

646667
def write_property_header(new_defs, env):
647-
filepath = os.path.join(env['src'], 'properties.gen.h')
648-
body = ''
668+
filepath = os.path.join(env['header_dir'], 'properties.gen.h')
669+
body = DONOTEDIT_MSG
649670
for filename, filecontent in new_defs['files'].items():
650671
classcontent = filecontent['content']
651672
for class_name_full, content in classcontent.items():

0 commit comments

Comments
 (0)