• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2025 Huawei Device Co., Ltd.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14cmake_minimum_required(VERSION 3.18)
15project(TaiheCompiler)
16
17# 设置 C 编译器为 clang
18set(CMAKE_C_COMPILER "clang")
19
20# 设置 C++ 编译器为 clang++
21set(CMAKE_CXX_COMPILER "clang++")
22
23# 设置 C++ 标准
24set(CMAKE_CXX_STANDARD 17)
25set(CMAKE_CXX_STANDARD_REQUIRED True)
26set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
27
28# 启用 ASan
29# if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
30#     # 添加编译和链接时的 ASan 选项
31#     add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
32#     add_link_options(-fsanitize=address)
33#     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address ")
34#     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address ")
35# endif()
36
37# 启用调试信息
38set(CMAKE_BUILD_TYPE Debug)
39
40# 为编译器设置 -fPIC
41set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
42set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
43
44set(TH_STDLIB_DIR "${CMAKE_SOURCE_DIR}/stdlib")
45
46# taihe runtime .c/.cpp path
47set(TH_RUNTIME_DIR "${CMAKE_SOURCE_DIR}/runtime")
48set(TH_RUNTIME_INCLUDE_DIR "${TH_RUNTIME_DIR}/include")
49set(TH_RUNTIME_SOURCE_DIR "${TH_RUNTIME_DIR}/src")
50
51# 设置 Python
52set(Python3_EXECUTABLE "/usr/bin/python3")
53find_package(Python3 REQUIRED COMPONENTS Interpreter)
54
55# 启用或禁用 coverage
56option(ENABLE_COVERAGE "Enable coverage run for the Python command" OFF)
57
58# 编译 taihe runtime 静态库
59set(TH_SOURCE
60  "${TH_RUNTIME_SOURCE_DIR}/string.cpp"
61  "${TH_RUNTIME_SOURCE_DIR}/object.cpp"
62  "${TH_RUNTIME_SOURCE_DIR}/runtime.cpp"
63)
64
65add_library(th_runtime STATIC ${TH_SOURCE})
66
67set_target_properties(th_runtime PROPERTIES
68  ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
69)
70
71target_include_directories(th_runtime PUBLIC ${TH_RUNTIME_INCLUDE_DIR})
72
73
74function(update_grammar)
75  add_custom_command(
76    OUTPUT ${CMAKE_SOURCE_DIR}/compiler/taihe/parse/antlr/TaiheAST.py
77    COMMAND ./generate-grammar
78    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/compiler # 设置工作目录
79    COMMENT "Update grammar"
80    DEPENDS ${CMAKE_SOURCE_DIR}/compiler/Taihe.g4
81  )
82
83  add_custom_target(UPDATE_GRAMMAR ALL
84    DEPENDS ${CMAKE_SOURCE_DIR}/compiler/taihe/parse/antlr/TaiheAST.py
85  )
86endfunction()
87
88
89function(generate_code_from_idl target_name idl_files gen_ets_files generated_dir taihe_configs)
90  set(IDL_FILES ${idl_files})
91  set(GEN_ETS_FILES ${gen_ets_files})
92
93  set(PROJ_HPP_FILES)
94  set(IMPL_HPP_FILES)
95  set(ABI_H_FILES)
96  set(ABI_C_FILES)
97  set(ANI_HPP_FILES)
98  set(ANI_CPP_FILES)
99
100  foreach(TAIHE_FILE ${IDL_FILES})
101    # 替换扩展名
102    get_filename_component(TAIHE_FILE_NAME ${TAIHE_FILE} NAME)
103
104    string(REGEX REPLACE "\\.taihe$" ".proj.hpp" PROJ_HPP_FILE ${TAIHE_FILE_NAME})
105    string(REGEX REPLACE "\\.taihe$" ".impl.hpp" IMPL_HPP_FILE ${TAIHE_FILE_NAME})
106    string(REGEX REPLACE "\\.taihe$" ".abi.h" ABI_H_FILE ${TAIHE_FILE_NAME})
107    string(REGEX REPLACE "\\.taihe$" ".abi.c" ABI_C_FILE ${TAIHE_FILE_NAME})
108    string(REGEX REPLACE "\\.taihe$" ".ani.hpp" ANI_HPP_FILE ${TAIHE_FILE_NAME})
109    string(REGEX REPLACE "\\.taihe$" ".ani.cpp" ANI_CPP_FILE ${TAIHE_FILE_NAME})
110
111    # 将修改后的文件名添加到新的列表中
112    list(APPEND PROJ_HPP_FILES "${generated_dir}/include/${PROJ_HPP_FILE}")
113    list(APPEND IMPL_HPP_FILES "${generated_dir}/include/${IMPL_HPP_FILE}")
114    list(APPEND ABI_H_FILES "${generated_dir}/include/${ABI_H_FILE}")
115    list(APPEND ABI_C_FILES "${generated_dir}/src/${ABI_C_FILE}")
116    list(APPEND ANI_HPP_FILES "${generated_dir}/include/${ANI_HPP_FILE}")
117    list(APPEND ANI_CPP_FILES "${generated_dir}/src/${ANI_CPP_FILE}")
118  endforeach()
119
120  if(ENABLE_COVERAGE)
121    list(APPEND COMMAND_TO_RUN "coverage" "run" "--parallel-mode" "-m")
122  else()
123    list(APPEND COMMAND_TO_RUN "python3" "-m")
124  endif()
125
126  list(APPEND COMMAND_TO_RUN
127    "taihe.cli.compiler"
128    "${idl_files}"
129    "-O" "${generated_dir}"
130    "--generate" "ani-bridge" "cpp-author" "pretty-print"
131    "${taihe_configs}"
132  )
133
134  add_custom_command(
135    OUTPUT ${PROJ_HPP_FILES} ${IMPL_HPP_FILES} ${ABI_H_FILES} ${ABI_C_FILES} ${ANI_HPP_FILES} ${ANI_CPP_FILES} ${GEN_ETS_FILES}
136    COMMAND ${COMMAND_TO_RUN}
137    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/compiler
138    DEPENDS ${IDL_FILES} ${CMAKE_SOURCE_DIR}/compiler/taihe/parse/antlr/TaiheAST.py
139    COMMENT "Generating Taihe C++ header and source files..."
140    VERBATIM
141  )
142
143  add_custom_target(${target_name}_gen
144    DEPENDS ${PROJ_HPP_FILES}
145    ${IMPL_HPP_FILES}
146    ${ABI_H_FILES}
147    ${ABI_C_FILES}
148    ${ANI_HPP_FILES}
149    ${ANI_CPP_FILES}
150    ${GEN_ETS_FILES}
151  )
152
153  set(${target_name}_PROJ_HPP_FILES ${PROJ_HPP_FILES} PARENT_SCOPE)
154  set(${target_name}_IMPL_HPP_FILES ${IMPL_HPP_FILES} PARENT_SCOPE)
155  set(${target_name}_ABI_H_FILES ${ABI_H_FILES} PARENT_SCOPE)
156  set(${target_name}_ABI_C_FILES ${ABI_C_FILES} PARENT_SCOPE)
157  set(${target_name}_ANI_HPP_FILES ${ANI_HPP_FILES} PARENT_SCOPE)
158  set(${target_name}_ANI_CPP_FILES ${ANI_CPP_FILES} PARENT_SCOPE)
159endfunction()
160
161# 准备 panda sdk
162function(setup_panda_sdk)
163  # 用户显式提供了 PANDA_HOME,不执行下载逻辑
164  if(DEFINED PANDA_HOME AND IS_DIRECTORY "${PANDA_HOME}")
165    message(STATUS "Using user-provided PANDA_HOME: ${PANDA_HOME}")
166    set(ENV{PANDA_HOME} "${PANDA_HOME}")
167    # 自动下载模式
168  else()
169    # 设置 PANDA 路径
170    set(PANDA_SDK_FILENAME "sdk-1.5.0-dev.36922.tgz")
171    set(PANDA_SDK_URL "https://nexus.bz-openlab.ru:10443/repository/koala-npm/%40panda/sdk/-/${PANDA_SDK_FILENAME}")
172    set(PANDA_EXTRACT_DIR "${CMAKE_SOURCE_DIR}/.panda_vm")
173    set(PANDA_SDK_PATH "${PANDA_EXTRACT_DIR}/${PANDA_SDK_FILENAME}")
174    set(PANDA_HOME "${PANDA_EXTRACT_DIR}/package/linux_host_tools")
175    set(PANDA_SDK_VERSION_FILE "${PANDA_EXTRACT_DIR}/package/version.txt")
176
177    file(MAKE_DIRECTORY "${PANDA_EXTRACT_DIR}")
178    string(REPLACE ".tgz" "" PANDA_SDK_VERSION "${PANDA_SDK_FILENAME}")
179
180    # 检查当前已提取版本
181    if(EXISTS "${PANDA_SDK_VERSION_FILE}")
182      file(READ "${PANDA_SDK_VERSION_FILE}" EXISTING_PANDA_SDK_VERSION)
183      string(STRIP "${EXISTING_PANDA_SDK_VERSION}" EXISTING_PANDA_SDK_VERSION)
184    else()
185      set(EXISTING_PANDA_SDK_VERSION "")
186    endif()
187
188    # 检查版本是否匹配
189    if(NOT "${EXISTING_PANDA_SDK_VERSION}" STREQUAL "${PANDA_SDK_VERSION}")
190      message(STATUS "Panda SDK version mismatch or not found. Expected: ${PANDA_SDK_VERSION}, Found: ${EXISTING_PANDA_SDK_VERSION}")
191      if(NOT "${PANDA_HOME}" STREQUAL "")
192        file(REMOVE_RECURSE "${PANDA_HOME}")
193      endif()
194      set(NEED_DOWNLOAD TRUE)
195    else()
196      set(NEED_DOWNLOAD FALSE)
197    endif()
198
199    # 如果需要重新准备 SDK
200    if(NEED_DOWNLOAD)
201      # 先检查本地是否已有对应的 SDK 包
202      set(LOCAL_SDK_PATH "${PANDA_EXTRACT_DIR}/${PANDA_SDK_VERSION}.tgz")
203      if(EXISTS "${LOCAL_SDK_PATH}")
204        message(STATUS "Found local Panda SDK package: ${LOCAL_SDK_PATH}")
205        set(PANDA_SDK_PATH "${LOCAL_SDK_PATH}")
206        set(NEED_ACTUAL_DOWNLOAD FALSE)
207      else()
208        message(STATUS "No local Panda SDK package found, will download: ${PANDA_SDK_FILENAME}")
209        set(NEED_ACTUAL_DOWNLOAD TRUE)
210      endif()
211
212      # 如果确实找不到,就去下载
213      if(NEED_ACTUAL_DOWNLOAD)
214        message(STATUS "Downloading Panda SDK: ${PANDA_SDK_FILENAME}")
215        execute_process(
216          COMMAND curl -u koala-pub:y3t!n0therP -L -o "${PANDA_EXTRACT_DIR}/${PANDA_SDK_FILENAME}" "${PANDA_SDK_URL}"
217          RESULT_VARIABLE DOWNLOAD_RESULT
218        )
219        if(NOT DOWNLOAD_RESULT EQUAL 0)
220          message(FATAL_ERROR "Failed to download Panda SDK!")
221        endif()
222        set(PANDA_SDK_PATH "${PANDA_EXTRACT_DIR}/${PANDA_SDK_FILENAME}")
223      endif()
224
225      # 删除原来的解压目录
226      file(REMOVE_RECURSE "${PANDA_HOME}")
227    endif()
228
229    # Extract Panda SDK if needed
230    if(NOT EXISTS "${PANDA_HOME}")
231      message(STATUS "Extracting Panda SDK from ${PANDA_SDK_PATH} ...")
232      execute_process(
233        COMMAND ${CMAKE_COMMAND} -E tar xzf "${PANDA_SDK_PATH}"
234        WORKING_DIRECTORY "${PANDA_EXTRACT_DIR}"
235        RESULT_VARIABLE EXTRACT_RESULT
236      )
237      if(NOT EXTRACT_RESULT EQUAL 0)
238        message(FATAL_ERROR "Failed to extract Panda SDK!")
239      endif()
240
241      # 保存当前版本信息
242      file(WRITE "${PANDA_SDK_VERSION_FILE}" "${PANDA_SDK_VERSION}")
243    endif()
244
245    # Set environment variable
246    set(ENV{PANDA_HOME} "${PANDA_HOME}")
247    set(PANDA_HOME "${PANDA_HOME}" PARENT_SCOPE)
248  endif()
249
250  # Set ETS compiler path
251  list(APPEND CMAKE_PROGRAM_PATH "$ENV{PANDA_HOME}/bin")
252
253  find_program(ETS_COMPILER es2panda)
254  find_program(ETS_RUNTIME ark)
255  find_program(ETS_DISASM ark_disasm)
256  find_program(ETS_LINK ark_link)
257
258  if(NOT ETS_COMPILER)
259    message(FATAL_ERROR "ets_compiler not found! Please set ETS_COMPILER_PATH or ensure ets_compiler is in your PATH.")
260  else()
261    message(STATUS "Found ets_compiler: ${ETS_COMPILER}")
262  endif()
263endfunction()
264
265
266# 编译动态库
267function(compile_dylib target_name include_dirs user_cpp_files)
268  set(ALL_SRC_FILES ${${target_name}_ABI_C_FILES} ${${target_name}_ANI_CPP_FILES} ${user_cpp_files})
269
270  foreach(author_source_file ${user_cpp_files})
271    foreach(impl_hpp_file ${${target_name}_IMPL_HPP_FILES})
272      set_source_files_properties(${author_source_file} PROPERTIES OBJECT_DEPENDS ${impl_hpp_file})
273    endforeach()
274  endforeach()
275
276  add_library(${target_name} SHARED ${ALL_SRC_FILES})
277
278  add_dependencies(${target_name} th_runtime ${target_name}_gen)
279  target_compile_options(${target_name} PRIVATE "-Wno-attributes")
280  set_target_properties(${target_name} PROPERTIES LINKER_LANGUAGE CXX)
281  target_link_libraries(${target_name} PRIVATE th_runtime)
282  target_link_options(${target_name} PRIVATE "-Wl,--no-undefined")
283  target_include_directories(${target_name} PUBLIC ${include_dirs} TH_RUNTIME_INCLUDE_DIR)
284endfunction()
285
286
287# 生成 arktsconfig.json
288function(write_arkts_config config_path ets_files)
289  foreach(file IN LISTS ets_files)
290    get_filename_component(file_name ${file} NAME)
291    string(REGEX REPLACE "\\.ets$" "" stripped_file "${file_name}")
292    set(entry "      \"${stripped_file}\": [\"${file}\"]")
293    list(APPEND ETS_PATH_ENTRIES "${entry}")
294  endforeach()
295
296  string(REPLACE ";" ",\n" ETS_PATH_ENTRIES_JOINED "${ETS_PATH_ENTRIES}")
297
298  file(WRITE "${config_path}"
299    "{\n"
300    "  \"compilerOptions\": {\n"
301    "    \"baseUrl\": \"${PANDA_HOME}\",\n"
302    "    \"paths\": {\n"
303    "      \"std\": [\"${PANDA_HOME}/../ets/stdlib/std\"],\n"
304    "      \"escompat\": [\"${PANDA_HOME}/../ets/stdlib/escompat\"],\n"
305    "${ETS_PATH_ENTRIES_JOINED}\n"
306    "    }\n"
307    "  }\n"
308    "}\n"
309  )
310endfunction()
311
312
313# 自定义 ETS 构建规则
314function(build_ets_target ets_file output_dir abc_file dump_file dep_ets_files dep_so_file build_demo_dir arktsconfig)
315  # 创建输出目录(如果不存在)
316  file(MAKE_DIRECTORY ${output_dir})
317
318  add_custom_command(
319    OUTPUT ${abc_file} # 输出文件
320    COMMAND ${ETS_COMPILER} ${ets_file}
321    --output ${abc_file}
322    --extension ets
323    --arktsconfig ${arktsconfig} # 生成命令
324    && ${ETS_DISASM} ${abc_file} ${dump_file}
325    DEPENDS ${ets_file} ${dep_ets_files} ${dep_so_file} ${arktsconfig} # 输入文件依赖
326    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} # 工作目录
327    COMMENT "Building ${ets_file} ETS target" # 注释
328  )
329endfunction()
330
331
332function(abc_link target_name ets_files build_demo_dir arktsconfig main_abc)
333  write_arkts_config(${arktsconfig} "${ets_files}")
334
335  set(ABC_FILES "")
336
337  set(BUILD_DIR "${build_demo_dir}/build")
338
339  # 为每个 ETS 文件创建编译目标
340  foreach(ETS_FILE ${ets_files})
341    get_filename_component(ETS_NAME_P ${ETS_FILE} NAME)
342    string(REGEX REPLACE "\\.[^.]*$" "" ETS_NAME "${ETS_NAME_P}")
343
344    set(ABC_FILE "${BUILD_DIR}/${ETS_NAME}.ets.abc")
345    set(DUMP_FILE "${BUILD_DIR}/${ETS_NAME}.ets.abc.dump")
346
347    build_ets_target(${ETS_FILE} ${BUILD_DIR} ${ABC_FILE} ${DUMP_FILE} "${ets_files}" ${target_name} ${build_demo_dir} ${arktsconfig})
348    list(APPEND ABC_FILES "${ABC_FILE}")
349  endforeach()
350
351  # 创建链接命令
352  add_custom_command(
353    OUTPUT ${main_abc}
354    COMMAND ${ETS_LINK} --output ${main_abc} -- ${ABC_FILES}
355    DEPENDS ${ABC_FILES}
356    COMMENT "Linking all ABC files to main.abc"
357  )
358endfunction()
359
360
361function(run_abc target_name build_demo_dir main_abc)
362  # 设置
363  file(MAKE_DIRECTORY ${build_demo_dir})
364  get_filename_component(target_name ${target_name} NAME_WE)
365
366  # 创建运行目标,并明确依赖于链接目标
367  add_custom_target(${target_name}_run ALL
368    WORKING_DIRECTORY ${build_demo_dir}
369    COMMAND # LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so
370    LD_LIBRARY_PATH=${build_demo_dir} ${ETS_RUNTIME}
371    --boot-panda-files=$ENV{PANDA_HOME}/../ets/etsstdlib.abc
372    --load-runtimes=ets ${build_demo_dir}/main.abc main.ETSGLOBAL::main
373    && echo "Run successful" || (echo "Run failed" && exit 1)
374    COMMENT "Running ${target_name}"
375    DEPENDS ${main_abc}
376  )
377endfunction()
378
379
380function(add_ani_demo target_name idl_files taihe_configs gen_ets_names user_ets_files user_include_dir user_cpp_files run_dir)
381  set(DEMO_DIR "${CMAKE_SOURCE_DIR}/${run_dir}/${target_name}")
382  set(BUILD_DEMO_DIR "${CMAKE_BINARY_DIR}/${run_dir}/${target_name}")
383  set(GEN_DIR "${BUILD_DEMO_DIR}/generated")
384  set(GEN_INCLUDE_DIR "${GEN_DIR}/include")
385  set(AUTHOR_INCLUDE_DIRS ${GEN_INCLUDE_DIR} ${user_include_dir})
386  set(BUILD_DIR "${BUILD_DEMO_DIR}/build")
387  set(ARKTSCONFIG "${BUILD_DEMO_DIR}/arktsconfig.json")
388  set(IDL_FILES ${idl_files} "${TH_STDLIB_DIR}/taihe.platform.ani.taihe")
389  set(GEN_ETS_NAMES ${gen_ets_names} "taihe.platform.ani.ets")
390  set(GEN_ETS_FILES "")
391  foreach(ETS_NAME ${GEN_ETS_NAMES})
392    set(ETS_FILE "${GEN_DIR}/${ETS_NAME}")
393    list(APPEND GEN_ETS_FILES "${ETS_FILE}")
394  endforeach()
395  set(ALL_ETS_FILES ${user_ets_files} ${GEN_ETS_FILES})
396  set(MAIN_ABC "${BUILD_DEMO_DIR}/main.abc")
397
398  # 生成代码
399  generate_code_from_idl(${target_name} "${IDL_FILES}" "${GEN_ETS_FILES}" ${GEN_DIR} "${taihe_configs}")
400  # 动态库编译
401  compile_dylib(${target_name} "${AUTHOR_INCLUDE_DIRS}" "${user_cpp_files}")
402  # 链接为 main.abc
403  abc_link(${target_name} "${ALL_ETS_FILES}" ${BUILD_DEMO_DIR} ${ARKTSCONFIG} ${MAIN_ABC})
404  # 运行
405  run_abc(${target_name} ${BUILD_DEMO_DIR} ${MAIN_ABC})
406endfunction()
407
408
409setup_panda_sdk()
410
411# INCLUDE_ANI_HEADER
412set(ANI_HEADER $ENV{PANDA_HOME}/../ohos_arm64/include/plugins/ets/runtime/ani)
413if(EXISTS "${ANI_HEADER}")
414  message(STATUS "Adding Panda include directory: ${ANI_HEADER}")
415  include_directories("${ANI_HEADER}")
416else()
417  message(FATAL_ERROR "Cannot find the path: ${ANI_HEADER}")
418endif()
419
420update_grammar()
421
422add_subdirectory(test)
423#add_subdirectory(cookbook)