banner
yono

yono

哈喽~欢迎光临
follow
github

CMAKEの合理化構造

について#

🎉ついに、keil の緑色の死体の圧力の下、会社は gcc コンパイラに移行する準備をしました。そして、gcc コンパイラチェーンの統合には CMAKE より良い選択肢はないと思います(もちろん EIDE プラグインも悪くはありません)。長い間独立して探求し、ついに keil を完全に排除しました。eclipse はまだ完全には排除できませんが、TI の MCU には CCS が必要です。いつ vscode が全面的に普及するのでしょうか?

最近、元のプロジェクトを完全な CMAKE プロジェクトに変換し、最適化できるプロジェクト構造のポイントをいくつか発見しました。

ツール#

ブログのファイルサービスページにはポータブル vscode のダウンロードがあるはずで、必要なツールがすべて統合されています。緑色のインストール不要です。

==1_初回起動時に実行してください.bat== というファイルがあり、ダブルクリックして実行すると、vscode がすぐに使えるようになります。このスクリプトの主な役割は、管理者モードに昇格し、各ツールチェーンのパスを自動的に環境変数に追加することです。

ファイルサービス - 土星環の基地

vscode ワークスペースの合理化#

.code-workspace ファイルの settings セクションに以下の部分を追加できます。

    "settings": {
        "C_Cpp.formatting": "clangFormat",
        "cmake.configureEnvironment": {
            "PROGRAM_NAME": "H7_GCC_PIONEER"
        }
    },

ここでは、フォーマッタとして clangFormat を指定しています。このフォーマッタの実行可能ファイルは ==1_初回起動時に実行してください.bat== の実行時に環境変数に追加されます。

CMAKE の環境変数を指定しました。これは生成される書き込みファイルの名前を設定するための便利な方法です。

主 cmakelist、つまりルートディレクトリには、以前次のような内容がありました。

set(CMAKE_PROJECT_NAME DebugBuild)

以下のように変更します。

if(DEFINED ENV{PROGRAM_NAME})
    set(CMAKE_PROJECT_NAME $ENV{PROGRAM_NAME})
else()
    message(WARNING "PROGRAM_NAME環境変数が設定されていません。デフォルトのプロジェクト名を使用します。")
    set(CMAKE_PROJECT_NAME "DefaultProjectName")
endif()

これにより、ワークスペースの.code-workspace ファイル内のPROGRAM_NAMEが優先されます。
この操作は、プロジェクトの開発者が CMAKE 関連のファイルをできるだけ変更しないようにするためのもので、今後もこの目的のための他の操作があります。

主なビルドの分岐#

CMAKE_BUILD_TYPE については、CMAKE プラグインから実際のビルドが渡されます。しかし、このビルドタイプに加えて、いくつかのカスタムビルドタイプも希望しています。以下の操作が可能です。

実行可能な主ビルドの前方にカスタム属性変数を使用します。

set(CMAKE_BUILD_BL "YES")
set(CMAKE_BUILD_BL "NO")

ツールチェーン指定ファイルでは、次のように操作できます(もちろん他のファイルでも同様で、主ビルドのこれらの属性変数はサブディレクトリやサブビルドに伝播します)。

if(CMAKE_BUILD_BL MATCHES YES)
    set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -T \"${CMAKE_SOURCE_DIR}/CPU/GNU/stm32H743XI_INCBL.ld\"")   # リンクスクリプトを追加
endif()
if(CMAKE_BUILD_BL MATCHES NO)
    set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -T \"${CMAKE_SOURCE_DIR}/CPU/GNU/stm32H743XI.ld\"")   # リンクスクリプトを追加
endif()

この操作により、2 つの異なるリンカースクリプトを制御します。YES の場合のリンカースクリプトは bootload 部分を含み、主に工場での書き込みに使用されます。NO の場合は bootload 部分を含まず、アップグレード用です。これにより、一部の操作が減少し、EIDE プラグインではこれほど便利にはできません。毎回手動でスクリプトを少し変更する必要があります。もちろん、開発者が CMAKE 関連のファイルをできるだけ変更しないようにするために、前述の操作のように新しい環境変数を作成することもできます。

主なビルドでの定義後のタスク#

私の主なビルドの最後には以下の 2 行があります。

# 個別のファイルにコンパイルフラグを追加
include("${CMAKE_CURRENT_LIST_DIR}/8_WorkSpace/CMake/toolCmake/extra-compile-flags.cmake")

# ビルド後のタスクを実行
include("${CMAKE_CURRENT_LIST_DIR}/8_WorkSpace/CMake/toolCmake/post-build-tasks.cmake")

extra-compile-flags.cmake#

このファイルの内容は以下の通りです。

include(${CMAKE_CURRENT_LIST_DIR}/cmake_func/functions.cmake)

set_compile_flags_for_matching_files(${CMAKE_PROJECT_NAME} "6_Rtos|7_Exlib" "-w")
set_compile_flags_for_matching_files(user_src "6_Rtos|7_Exlib" "-w")

主ビルドプロジェクト${CMAKE_PROJECT_NAME}およびソースを含むプロジェクトuser_srcに関して、6_Rtos または 7_Exlib フォルダ内のソースにすべて-wのコンパイルフラグを追加することを目的としています。これはすべての警告を無視することを意味します。私たちは超厳格な全警告を有効にしているため、オペレーティングシステムや他の人が書いたライブラリにはいくつかの警告があるかもしれません。非常に煩わしく、変更できないため、このような操作があります。注意すべきは、ソースを含むプロジェクトuser_srcは元々すべての部分がINTERFACE属性で定義されているため、user_src内のソースには正常にコンパイルフラグを追加できないことです。そのため、target_sources部分は現在PUBLIC属性で定義されるべきであり、受け入れられない副作用はまだ発見されていません。

最初の引数はプロジェクト名、2 番目の引数はこれらのフィールドを含むソースファイルのパス、3 番目の引数は追加したいコンパイルフラグです。これにより新しいファイル functions.cmake が導入されます。

# FUNC

# ヘッダーファイルを再帰的に含む関数
function(include_sub_directories_recursively root_dir)
    if (IS_DIRECTORY ${root_dir})               # 現在のパスがディレクトリか?そうであれば、含むディレクトリに追加
        message("include dir: " ${root_dir})
        target_include_directories(${PROJECT_NAME} INTERFACE
        ${root_dir}
        )
    endif()

    file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*) # 現在のディレクトリ内のすべてのファイルを取得
    foreach(sub ${ALL_SUB})
        if (IS_DIRECTORY ${root_dir}/${sub})
            include_sub_directories_recursively(${root_dir}/${sub}) # サブディレクトリに再帰的に呼び出し
        endif()
    endforeach()
endfunction()

# 特定のターゲットに、パスにキーワードを含むソースファイルに期待されるフラグを追加
function(set_compile_flags_for_matching_files target_name keywords compile_flags)
    # ターゲットの元のソースファイルリストを取得
    get_target_property(src_list ${target_name} SOURCES)

    # ターゲットが存在し、ソースファイルがあるか確認
    if(NOT src_list)
        message(WARNING "ターゲット '${target_name}' は存在しないか、ソースがありません。")
        return()
    endif()

    # コンパイルフラグを設定する必要があるファイルを格納する新しいリストを作成
    set(filtered_src_list)

    # 元のソースファイルリストをループし、必要なファイルをフィルタリング
    foreach(src_file IN LISTS src_list)
        if("${src_file}" MATCHES "${keywords}")
            list(APPEND filtered_src_list ${src_file})
        endif()
    endforeach()

    # フィルタリングされたソースファイルにコンパイルフラグを設定
    foreach(src_file IN LISTS filtered_src_list)
        set_source_files_properties(${src_file} PROPERTIES COMPILE_FLAGS "${compile_flags}")
    endforeach()
endfunction()


# FUNC END

これは私が cmake 関数を書くために専用に作成したファイルですが、特に説明はしません。必要なときに関数を include します。

post-build-tasks.cmake#

このファイルはビルド後のタスクを管理するためのもので、内容は以下の通りです。

# ビルド後のタスクを個別に管理

# ツールチェーンツールを定義
set(OBJCOPY arm-none-eabi-objcopy)
set(OBJDUMP arm-none-eabi-objdump)

# カスタムコマンドを追加してbinおよびhexファイルを生成
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
    COMMAND ${OBJCOPY} -O binary $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_PROJECT_NAME}.bin
    COMMAND ${OBJCOPY} -O ihex $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_PROJECT_NAME}.hex
    COMMAND  ${CMAKE_CURRENT_LIST_DIR}/gccMapView.exe ${CMAKE_BINARY_DIR}
    COMMENT "elfからbinおよびhexファイルを生成中"
)

これは bin ファイルと hex ファイルを生成するためのものです。
その後、gccMapView.exe を実行しました。これは私が map を整理するために作った小さなソフトウェアです。GCC のオリジナルの map は本当に醜いので、この小さなソフトウェアがあります。オープンソースのアドレスはここにあり、効果は非常に良好です。

stbanana/gcc-elf-link-sort: A tool for sorting the symbols of .elf by address

原 map.png

整理出力.png

プロジェクトソースの自動化による導入#

プロジェクトソースはヘッダーファイルのパスを遍歴し、含まれています。以下の部分があります。

# cmake FUNC
include(${CMAKE_CURRENT_LIST_DIR}/cmake_func/functions.cmake)

# ヘッダーファイルを再帰的に含む
include_sub_directories_recursively(${CMAKE_CURRENT_LIST_DIR}/../../../1_App)
include_sub_directories_recursively(${CMAKE_CURRENT_LIST_DIR}/../../../2_Contorl)
include_sub_directories_recursively(${CMAKE_CURRENT_LIST_DIR}/../../../3_Module)
include_sub_directories_recursively(${CMAKE_CURRENT_LIST_DIR}/../../../4_Driver)

これは cmake 関数を呼び出すため、統一された関数定義ファイルにあり、これら 4 つのフォルダ内のすべてのパスを含むサブディレクトリを追加します。

さらに、以下の部分があります。

# すべてのソースファイルを再帰的に検索
file(GLOB_RECURSE 1_APP_SRC ${CMAKE_CURRENT_LIST_DIR}/../../../1_App/*.c)
file(GLOB_RECURSE 2_CONTORL_SRC ${CMAKE_CURRENT_LIST_DIR}/../../../2_Contorl/*.c)
file(GLOB_RECURSE 3_MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/../../../3_Module/*.c)
file(GLOB_RECURSE 4_DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/../../../4_Driver/*.c)
file(GLOB_RECURSE 5_DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/../../../5_PhysicalChip/Stm32H7/*.c)

target_sources(${CMAKE_PROJECT_NAME} PUBLIC
    ../../../main.c
    ${1_APP_SRC}
    ${2_CONTORL_SRC}
    ${3_MODULE_SRC}
    ${4_DRIVER_SRC}
    ${5_DRIVER_SRC}
)

これはこれら 4 つのフォルダ内のすべてのソースをソースファイルに追加することを目的としています。

さらに、より低レベルの RTOS やライブラリの部分については、ソースと include パスを手動で指定しています。

これを行った後、すべての不要なビジネスソースを自由に作成および変更できるようになりました。以前は名前を変更したり構造を変更したりするために多くのプロジェクト設定を変更する必要がありましたが、今ではビジネスコードを完全にスムーズに開発できるようになりました。ビジネスコードとドライバサポートはさらに分離されました。

ここで前述の変更があり、target_sources部分は現在PUBLIC属性で定義されるべきです。そうでなければ、個別のファイルのコンパイルフラグを指定できません。INTERFACE属性は実際のコンパイル中に行われ、主ビルドプロジェクトに掛かりますが、CMAKE システム内ではこのファイルインスタンスが存在しません。本質的に、これはソースを含むプロジェクトuser_srcに仮に掛かっていますが、user_srcINTERFACEインターフェースの仮ライブラリであり、実際にはコンパイルされないため、すべてのソースはプロジェクトuser_src全体として主ビルドプロジェクトにリンクされ、正確なファイルを見つけることができず、単に主ビルドプロジェクトのコンパイルフラグを継承してコンパイルに参加します。

この記事は Mix Space によって xLog に同期更新されました。
元のリンクは https://www.yono233.cn/posts/novel/24_11_25_CMAKE%E7%9A%84%E5%90%88%E7%90%86%E5%8C%96%E7%BB%93%E6%9E%84


読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。