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)