Files
build_infra/0_cmake_library/create_linux_driver_proj.cmake
T
2026-06-16 10:23:51 +08:00

286 lines
9.7 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function(_get_path_relation path1 path2 result)
# 初始值设置为 0,表示没有包含关系
set(${result} 0 PARENT_SCOPE)
# 判断 path2 是否包含 path1
string(FIND "${path2}" "${path1}" _idx)
if(_idx GREATER -1)
# 如果 path2 包含 path1,设置 result 为 2path2 是父路径)
set(${result} 1 PARENT_SCOPE)
else()
# 如果没有包含关系,检查 path1 是否包含 path2
string(FIND "${path1}" "${path2}" _idx)
if(_idx GREATER -1)
# 如果 path1 包含 path2,设置 result 为 1path1 是父路径)
set(${result} 2 PARENT_SCOPE)
endif()
endif()
endfunction()
# 写成宏是为了能直接修改 list_var 所代表的变量
macro(_handle_path_add list_var path)
# 创建一个列表用于记录需要删除的路径
set(need_remove_list)
set(need_add 1)
# 遍历列表中的路径,检查与新路径的包含关系
foreach(li ${${list_var}})
set(relation 0)
# 获取路径之间的包含关系
_get_path_relation(${path} ${li} relation)
if (relation EQUAL 2)
# 如果新路径是父路径,跳过添加
#message("${path} 被 ${li} 包含,跳过添加")
set(need_add 0)
break()
elseif (relation EQUAL 1)
# 如果新路径包含旧路径,记录旧路径需要移除
list(APPEND need_remove_list ${li})
#message(" ${li} 被 ${path} 包含,移除旧的路径 ${li}")
endif()
endforeach()
# 删除已标记的路径
foreach(remove_path ${need_remove_list})
list(REMOVE_ITEM ${list_var} ${remove_path})
#message("已从 ${list_var} 中删除路径:${remove_path}")
endforeach()
# 如果需要添加新路径,将其添加到列表
if (need_add)
list(APPEND ${list_var} ${path})
#message("将路径 ${path} 添加到 ${list_var}")
endif()
endmacro()
function(get_common_path list_var out_var)
# 空列表直接返回空
list(LENGTH ${list_var} _path_count)
if(_path_count EQUAL 0)
set(${out_var} "" PARENT_SCOPE)
return()
endif()
# 取第一个路径作为初始公共路径
list(GET ${list_var} 0 _first_path)
string(REPLACE "\\" "/" _first_path "${_first_path}")
# 检查路径是否以 / 开头
set(_has_leading_slash 0)
if("${_first_path}" MATCHES "^/.*")
set(_has_leading_slash 1)
endif()
# 将路径拆分为部分
string(REPLACE "/" ";" _common_parts "${_first_path}")
# 遍历所有路径
foreach(_path IN LISTS ${list_var})
string(REPLACE "\\" "/" _path_norm "${_path}")
string(REPLACE "/" ";" _cur_parts "${_path_norm}")
# 取两个列表的较小长度,避免越界
list(LENGTH _common_parts _len1)
list(LENGTH _cur_parts _len2)
if(_len1 LESS _len2)
set(_min_len ${_len1})
else()
set(_min_len ${_len2})
endif()
# 没有可比部分,直接公共路径为空
if(_min_len EQUAL 0)
set(_common_parts "")
break()
endif()
math(EXPR _stop "${_min_len} - 1")
set(_new_common_parts "")
foreach(_idx RANGE 0 ${_stop})
list(GET _common_parts ${_idx} _part1)
list(GET _cur_parts ${_idx} _part2)
if(_part1 STREQUAL _part2)
list(APPEND _new_common_parts "${_part1}")
else()
break()
endif()
endforeach()
set(_common_parts ${_new_common_parts})
# 已经没有公共部分了,提前结束
list(LENGTH _common_parts _common_len)
if(_common_len EQUAL 0)
break()
endif()
endforeach()
# 拼回路径
if(_common_parts)
list(JOIN _common_parts "/" _common_path)
else()
set(_common_path "")
endif()
# 如果原路径有前导 '/', 在拼接回路径时添加它
if(_has_leading_slash)
set(_common_path "/${_common_path}")
endif()
set(${out_var} "${_common_path}" PARENT_SCOPE)
endfunction()
# 目前是远程开发所以 无需把源码复制一遍 扫描到公共目录直接使用即可
function(_create_linux_driver_proj_ex driver_name _target_list_var_name_)
# 此函数用于安装源码 同时创建 component 也可加入到cpack 安装包里
__check_none_extr_params(${ARGC} "${ARGN}" "${ARGV}")
__bfs_traverse_targets(_dependency_list_ ${_target_list_var_name_} _relys_)
set(_top_level_dir_list)
# 计算出公共路径,以及要复制的文件
foreach (_rely_ ${_relys_})
get_property(_attach_include_list_ TARGET ${_rely_} PROPERTY _attach_include_list_)
foreach (_rely_dir_ ${_attach_include_list_})
get_filename_component(_base_name_ "${_rely_dir_}" NAME)
_handle_path_add(_top_level_dir_list ${_rely_dir_})
endforeach()
get_property(_attach_source_list_ TARGET ${_rely_} PROPERTY _attach_source_list_)
foreach (_rely_dir_ ${_attach_source_list_})
_handle_path_add(_top_level_dir_list ${_rely_dir_})
endforeach()
get_property(_attach_file_list_ TARGET ${_rely_} PROPERTY _attach_file_list_)
foreach (_rely_file_ ${_attach_file_list_})
_handle_path_add(_top_level_dir_list ${_rely_file_})
endforeach()
endforeach()
message("_top_level_dir_list: ${_top_level_dir_list}")
# 调用函数计算公共路径
set(common_path)
get_common_path(_top_level_dir_list common_path)
# 输出结果
message("公共路径: ${common_path}")
set(Makefile "# 基础模块指令\n")
foreach (_rely_ ${_relys_})
set(_rely_file_list_)
get_property(_attach_source_list_ TARGET ${_rely_} PROPERTY _attach_source_list_)
foreach (_rely_dir_ ${_attach_source_list_})
file(GLOB_RECURSE _cur_rely_file_list_ "${_rely_dir_}/*.c" "${_rely_dir_}/*.cpp" )
list(APPEND _rely_file_list_ ${_cur_rely_file_list_})
endforeach()
get_property(_attach_file_list_ TARGET ${_rely_} PROPERTY _attach_file_list_)
list(APPEND _rely_file_list_ ${_attach_file_list_})
#message("_rely_ 【${_rely_}】 attach_source_list:【${_attach_source_list_}】 attach_file_list【${_attach_file_list_}】 ")
set(rely_objs "objs_${_rely_} :=")
set(new_prefix "")
foreach (_rely_file_ ${_rely_file_list_})
file(RELATIVE_PATH _rel_path "${common_path}" "${_rely_file_}")
get_filename_component(_dir "${_rel_path}" DIRECTORY)
get_filename_component(_name "${_rel_path}" NAME_WLE)
if(_dir STREQUAL "")
set(_new_path "${new_prefix}${_name}.o")
else()
set(_new_path "${new_prefix}${_dir}/${_name}.o")
endif()
# message("src = ${_rely_file_}")
# message("dst = ${_new_path}")
#message(" ${_new_path}")
string(APPEND rely_objs " ${_new_path}")
endforeach()
string(APPEND Makefile "${rely_objs}\n")
endforeach()
string(APPEND Makefile "\n# 内核模块组合指令\n")
foreach(target ${${_target_list_var_name_}})
set(_temp_list_ ${target})
set(_cur_relys_)
# 获取单个目标的relys
__bfs_traverse_targets(_dependency_list_ _temp_list_ _cur_relys_)
set(target_name "ko_${target}")
string(APPEND Makefile "obj-m += ${target_name}.o\n")
set(cur_target "${target_name}-y := ")
foreach(cur_rely ${_cur_relys_})
string(APPEND cur_target " $(objs_${cur_rely})")
endforeach()
message("${target} cur_relys ${_cur_relys_}")
string(APPEND Makefile "${cur_target}\n")
endforeach()
string(APPEND Makefile "\n# 综合指令")
string(APPEND Makefile "
KDIR ?= /lib/modules/$(shell uname -r)/build
MKFILE_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
OUT := $(MKFILE_DIR)/out
all:
mkdir -p $(OUT)
$(MAKE) -C $(KDIR) M=$(MKFILE_DIR) MO=$(OUT) V=1 modules
clean:
$(MAKE) -C $(KDIR) M=$(MKFILE_DIR) MO=$(OUT) clean
rm -rf $(OUT)
compdb: all
$(MAKE) -C $(KDIR) M=$(MKFILE_DIR) MO=$(OUT) compile_commands.json
")
add_custom_target(${driver_name}_all
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${common_path}" all
WORKING_DIRECTORY "${common_path}"
COMMENT "Build linux driver ${driver_name}"
VERBATIM
)
add_custom_target(${driver_name}_clean
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${common_path}" clean
WORKING_DIRECTORY "${common_path}"
COMMENT "Clean linux driver ${driver_name}"
VERBATIM
)
add_custom_target(${driver_name}_compdb
COMMAND ${CMAKE_MAKE_PROGRAM} -C "${common_path}" compdb
WORKING_DIRECTORY "${common_path}"
COMMENT "Generate compile_commands.json for ${driver_name}"
VERBATIM
)
#要生成 compile_commands.json 来生成对应的cmake选项从而cmake有语法提示
#message("【\n${Makefile}】")
#message("Makefile安装在 ${install_prefix}")
#file(WRITE "${install_prefix}" "${Makefile}")
message("Makefile安装在公共路径下 ${common_path}")
file(WRITE "${common_path}/Makefile" "${Makefile}")
endfunction()
function(_create_linux_driver_proj driver_name)
set(_temp_list_ "${ARGN}")
_create_linux_driver_proj_ex(${driver_name} _temp_list_)
endfunction()
# 【内核驱动调试接口与使用方法入门】 https://zhuanlan.zhihu.com/p/1922942186057635216
# 【Linux内核kgdb实战:内核源码级调试工具】 https://zhuanlan.zhihu.com/p/1962870670770835660