Разработка софта это не только про код. Разработка софта это во многом про Toolchain(ы). Прежде чем начать исполняться исходники проходят гигантский путь и с каждым годом выходят все более и более массивные системы сборки. Современные технологии разработки софта настолько многостадийные, что понять их не просто.
Toolchain это как длинный конвейер. Есть действия, которые следуют одни за другими. После чего получается результат (артефакты). Большинство IDE(IAR, KEIL, MsVisualStudio и пр.) скрывают весь этот конвейер преобразования файлов. И программисты, которые привыкли торчать в IDE(шках) часто даже не догадываются, что в программировании существует что-то кроме *.h и *.с файликов. В этом плане IDE оказывают своим покупателям медвежью услугу, так как программисты привыкшие работать только в IDE имеют тенденцию становиться очень слабыми разработчиками.
По-настоящему разобраться как варятся артефакты сложно. Как же это сделать?
Надо прибегнуть к народной мудрости. Как говорит английская пословица: "картинка стоит тысячи слов". Значит надо нарисовать картинку, то есть схему ToolChain(а).
Зачем нужны эти пресловутые схемы ToolChain(ов)?
1--Например фирма chip maker может получить преимущество на рынке, если у нее есть качественная, понятная, доступная и разнообразная документация.
2--Схема ToolChain(а) позволит быстро ввести в курс дела нового сотрудника-программиста в компании.
Как же нарисовать схему ToolChain(а)? Тут есть 2 варианта:
[1] Рисовать схему самому, мышкой в программе Inkscape.exe.
Плюс:
a) Можно добиться очень высокой степени изобразительности и гибкости. Как тут.
![Схем ToolChain нарисованная от руки Схем ToolChain нарисованная от руки](https://habrastorage.org/getpro/habr/upload_files/2b9/06e/039/2b906e0393c864993a60dd949b1c51fa.png)
Можно задействовать слои, линейки. Те кто учил в художественной школе композицию тут могут оторваться по-полной.
Минусы:
a) Ручное рисование весьма утомительно. Обязательно наступят боли в запястье.
b) Использование мышки в программировании вообще считается дурным тоном.
c) Трудно подвергнуть *.svg файл версионному контролю. Конфликты при git merge *.svg так как это, в сущности, *.xml(ка).
d) Трудно вставить новый блок так как надо всё снова двигать, выравнивать.
[2] Составить описание графа или дерева на языке разметки графов Dot и автоматически одноименной утилитой dot.exe сгенерировать схему графа.
Плюсы:
a) Быстро.
b) Четко.
c) Легко перерисовать. Легко вставить новый блок.
d) Легко подвергнуть версионному контролю.
e) Легко распределить между разными разработчиками сложной блок-схемы.
Минусы:
a) Надо очень хорошо знать синтаксис и семантику языка Dot. Это кластеры, свойства вершин, свойства ребер, способы раскраски (названия цветов), свойства начала линий, свойства конца линий. Ранги узлов. Настройки авто трассировки и прочее.
b) Схема может не скомпилироваться рендером, если есть ошибки в синтаксисе языка Dot.
c) Cхема может отрисоваться (отрендериться) самым неожиданным для автора образом.
Тем не менее, как по мне, второй вариант выглядит намного предпочтительнее и позитивнее так как надо меньше пользоваться мышкой. Да и к схемам Toolchain(а) обычно не предъявляют требований высокой степени художественности. Лишь бы поскорее понять как работать с кучей разрозненных утилит.
Какой инструментарий потребуется для авто генерации блок схем?
Если коротко, то это cpp, dot, make, chrome.
Прежде всего надо накатить компилятор Dot файлов. Советую брать с официального сайта https://graphviz.org/. Сейчас там версия 6.0.1. Можно конечно и из CygWin скачать Dot, но там версия устаревшая. Старый Dot может упасть в run-time из-за переполнения стека при отрисовке сложных графов. Не забываем прописать путь к dot.exe в переменную PATH.
Писать код на голом языке Dot это не эффективно. В реальных схемах слишком много повторяющихся синтаксических конструкций. Поэтому объединим Си(ишный) препроцессор (утилита cpp.exe) с языком dot.
С препроцессору (cpp.exe) вообще все равно какой там язык (assembler, C, C++, DeviceTree, Kconfig, скрипты компоновщика *.ld). Задача утилиты cpp.exe это банальная вставка и замена текста и точка. Например деревья устройств в Linux тоже обрабатываются препроцессором cpp. И это всех более чем устраивает. Поэтому будем и мы также использовать препроцессор cpp для обработки и подготовки исходного текста на языка dot.
В качестве примера исследуемого сложного ToolChain(а) рассмотрим Zephyr project.
Определим только несколько полезных макросов для языка dot
#ifndef TOOLCHAIN_UTILS_H
#define TOOLCHAIN_UTILS_H
#define BINARY [fillcolor = turquoise1]
#define GENERATED [fillcolor = moccasin]
#define SRC [style="filled"][fillcolor = green]
#define TOOL [shape = box][style="filled"]
#define SCRIPT [shape = box][style="filled"] [fillcolor = plum1]
#define FILE [shape = note][fillcolor = gold][style="filled"]
#define DEVICE [shape = box][fillcolor = grey][style="filled"]
#endif /* TOOLCHAIN_UTILS_H */
Определим файл *.doti с утилитами, которые будут участвовать в ToolChain(е). *.doti - значит, что это include.
west [label="west.py"] SCRIPT
scripts_kconfig [label="zephyr/scripts/kconfig.py"] SCRIPT
menuconfig [label="menuconfig.py"] SCRIPT
gen_defines_py [label="gen_defines.py"] SCRIPT
buildprog [label="buildprog.py"]SCRIPT
guiconfig [label="guiconfig.py"] SCRIPT
clang_format [label="clang-format.exe"] TOOL
eclipse [label="Eclipse.exe"] TOOL
eclipsec [label="eclipsec.exe"] TOOL
bash [label="bash.exe"] TOOL
hexdump [label="hexdump.exe"] TOOL
browser [label="chrome.exe"] TOOL
inkscape [label="Inkscape.exe"] TOOL
nrfjprog [label="nrfjprog.exe"] TOOL
Cppcheck [label="Cppcheck.exe"] TOOL
dtc [label="dtc"] TOOL
readelf [label="readelf.exe"]TOOL
cpp_ld[label="cpp.exe"] TOOL
jenkins [label="jenkins.exe"]TOOL
cpp [label="cpp.exe"]TOOL
chocolatey [label="chocolatey.exe"]TOOL
git [label="git.exe"]TOOL
JLinkGDBServer [label="JLinkGDBServer.exe"]TOOL
cpp_dot [label="cpp.exe"] TOOL
cpp_3 [label="cpp.exe (preproc)"] TOOL
linker [label="ld.exe (linker)"] TOOL
compiler [label="gcc.exe (ARM Compiler)"] TOOL
NotePadPp [label="Notepad++.exe"] TOOL
cmd [label="cmd.exe"] TOOL
GDB [label="gdb.exe"] TOOL
cMake [label="cmake.exe"] TOOL
GN [label="gn.exe"] TOOL
nrfjprog [label="nrfjprog.exe"] TOOL
Python [label="Python.exe"] TOOL
make [label="make.exe"] TOOL
ninja [label="ninja.exe"] TOOL
objcopy [label="objcopy.exe"] TOOL
as [label="as.exe"]TOOL
nm [label="nm.exe"]TOOL
addr2line [label="addr2line.exe"]TOOL
dot [label="dot.exe"]TOOL
ar [label="ar.exe"]TOOL
//{ rank = same; ninja; make;}
Определим *.doti файл со списком расширений файлов, которые будут участвовать в ToolChain(е)
dtsi[label="*.dtsi"] FILE SRC
DotConf[label="*.conf (Kernel configuration)"] FILE SRC
bat_file[label="*.bat"] FILE SRC
CMakeLists [label="CMakeLists.txt "] FILE SRC
sh_file[label="*.sh"] FILE SRC
Kconfig_defaults[label="Kconfig.defaults"] FILE SRC
ld_file[label="*.ld"] FILE SRC
mk_file[label="*.mk"] FILE SRC
h_file[label="*.h"] FILE SRC
c_file[label="*.c"] FILE SRC
dot_file[label="*.dot"] FILE SRC
doti_file[label="*.doti"] FILE SRC
yaml[label="*.yaml"] FILE SRC
Kconfig [label="Kconfig"] FILE SRC
dts[label="*.dts"] FILE SRC GENERATED
zephyr_dts_pre[label="zephyr.dts.pre"] FILE GENERATED
cproject [label=".cproject "] FILE GENERATED
project [label=".project (description file)"] FILE GENERATED
Kconfig_zephyr[label="Kconfig.zephyr"] FILE
txt_file[label="*.txt"] FILE
CMakeCache_txt [label="CMakeCache.txt"] FILE GENERATED
map_file[label="*.map"] FILE GENERATED
hex_file[label="*.hex"] FILE GENERATED
obj_file[label="*.o"] FILE GENERATED BINARY
a_file[label="*.a"] FILE GENERATED BINARY
elf_file[label="*.elf"] FILE GENERATED BINARY
dtb_file[label="*.dtb"] FILE GENERATED BINARY
bin_file[label="*.bin"] FILE GENERATED BINARY
build_ninja [label="build.ninja"] FILE GENERATED
json_file[label="*.json"] FILE
svg_file[label="*.svg "] FILE GENERATED
west_yml[label="west.yml (manifest file)"] FILE
MakeFile[label="Makefile"] FILE GENERATED
devicetree_generated_h[label="devicetree_generated.h"] FILE GENERATED
zephyr_dts[label="zephyr.dts"] FILE GENERATED
autoconfig_h [label="autoconfig.h"] FILE GENERATED
s_file [label="*.S"] FILE GENERATED
gn_file [label="BUILD.gn"] FILE
cmd_file [label="*.cmd"] FILE
pp_file [label="*.pp"] FILE GENERATED
DotConfig [label=".config"] FILE GENERATED
cmake_file[label="*.cmake"] FILE
defconfig_file[label="*.defconfig"] FILE
Определим файл со связями утилит и файлов между собой.
#include "ToolChain_utils.doti"
digraph graphname {
rankdir=TB;
splines=ortho;
#include "ToolChain_nRF5340_hardware.doti"
subgraph cluster_NetTop {
style=filled;
color=aliceblue;
label = "NetTop (WorkStation Computer)";
HostCpu
HOST_USB
subgraph cluster_Windows10 {
style=filled;
color=lightblue;
label = "Windows10";
#include "ToolChain_nRF5340_tools.doti"
#include "ToolChain_nRF5340_files.doti"
NotePadPp->bat_file[label="*.bat"][dir="both"]
NotePadPp->doti_file[label="*.doti"] [dir="both"]
NotePadPp->sh_file[label="*.sh"][dir="both"]
NotePadPp->mk_file[label="*.mk"][dir="both"]
NotePadPp->c_file[label="*.c"][dir="both"]
NotePadPp->h_file[label="*.h"][dir="both"]
bat_file->cmd[label="*.bat"]
sh_file->bash[label="*.sh"]
subgraph cluster_JVM {
style=filled;
color=lightgreen;
label = "JVM";
jenkins->bash
eclipsec
cproject->eclipse[label=".cproject"][dir="both"]
project->eclipse[label=".project"][dir="both"]
}
subgraph cluster_BuildConfig {
style=filled;
color=khaki1;
label = "Build Configuration (buildsystem)";
bash->buildprog
cmd->buildprog
Python->buildprog
json_file->buildprog [label="*.json"]
west_yml->west[label="west.yml"]
Python->west
buildprog->west[label="?"]
yaml->gen_defines_py[label="*.yaml"]
dtsi->cpp[label="*.dtsi"]
dts->cpp
cpp->zephyr_dts_pre
zephyr_dts_pre ->gen_defines_py[label="zephyr.dts.pre"]
gen_defines_py->zephyr_dts[label="zephyr.dts"]
gen_defines_py->devicetree_generated_h[label="devicetree_generated.h"]
zephyr_dts->dtc
dtc->dtb_file[label="*.dtb"]
CMakeLists->cMake[label="CMakeLists.txt"]
west->cMake
west->scripts_kconfig
cMake->CMakeCache_txt[label="CMakeCache.txt"] [dir="both"]
gn_file->GN
GN->build_ninja
cMake->build_ninja[label="build.ninja"]
cMake->MakeFile
west->menuconfig [label="build -t"]
Kconfig_defaults->Kconfig[label="Kconfig.defaults"]
Kconfig->Kconfig_zephyr
west->guiconfig[label="build -t"]
Kconfig->scripts_kconfig[label="Kconfig"]
DotConf->scripts_kconfig[label="*.conf"]
scripts_kconfig->autoconfig_h[label="autoconfig.h"]
scripts_kconfig->DotConfig[label="*.config"]
DotConfig->menuconfig[label="*.config"][dir="both"]
DotConfig->guiconfig[label="*.config"][dir="both"]
}//cluster_BuildConfig
ld_file->git[label="*.ld"][dir="both"]
sh_file->git[label="*.sh"][dir="both"]
h_file->git[label="*.h"][dir="both"]
c_file->git[label="*.c"][dir="both"]
mk_file->git[label="*.mk"][dir="both"]
doti_file->git[label="*.doti"][dir="both"]
cproject->git[label=".cproject"][dir="both"]
MakeFile->git[label="Makefile"][dir="both"]
project->git[label=".project"][dir="both"]
c_file->eclipse[label="*.c "]
h_file->eclipse[label="*.h"]
eclipse->c_file[label="*.c "]
eclipse->h_file[label="*.h"]
eclipse->MakeFile[dir="both"][label="Makefile"]
eclipse->mk_file[dir="both"][label="*.mk"]
cMake-> project
cMake-> cproject
#include "ToolChain_nRF5340_build_artefacts.doti"
subgraph cluster_BuildDoc {
style=filled;
color=beige;
label = "Build Documentation";
doti_file->cpp_dot
cpp_dot->dot_file
dot_file->dot
dot->svg_file[label="*.svg"]
svg_file->browser[label="*.svg"]
svg_file->inkscape[label="*.svg"]
}
clang_format->c_file[label="*.c"][dir="both"]
clang_format->h_file[label="*.h"][dir="both"]
h_file->Cppcheck[label="*.h"]
c_file->Cppcheck[label="*.c"]
browser->jenkins[label="8080"]
}//Win10
//NotePadPp->Monitor
}//NetTop
eclipse->Monitor
nrfjprog->HOST_USB
JLinkGDBServer->HOST_USB
subgraph cluster_Board {
style=filled;
color=lightblue;
label = "Board";
USB_CONNECTOR_BOARD
Programmator
TargetMcu
}
}
Теперь надо собрать, собственно, сам *.dot файл для утилиты рендера dot.exe, преобразовать *.dot в векторную графику *.svg и отобразить рисунок на экране монитора прямо в браузере. Вот такой микро-конвейер надо реализовать.
![](https://habrastorage.org/getpro/habr/upload_files/0f9/7ad/16a/0f97ad16aa9ca36e8c8f9a1010a3cb2c.png)
Тут нам как раз поможет утилита make. Вот ее код
#CC=C:/cygwin64/bin/dot.exe
CC_DOT="C:/Program Files/Graphviz/bin/dot.exe"
RENDER="C:/Program Files/Google/Chrome/Application/chrome.exe"
#RENDER=chrome.exe
CURRENT_DIR = $(shell pwd)
$(info CURRENT_DIR= $(CURRENT_DIR) )
CURRENT_DIR := $(subst /c/,C:/, $(CURRENT_DIR))
$(info CURRENT_DIR=$(CURRENT_DIR) )
SOURCES_DOT += $(CURRENT_DIR)/ToolChain_nRF5340.doti
SOURCES_DOT_RES += $(CURRENT_DIR)/ToolChain_nRF5340_res.dot
SOURCES_DOT := $(subst /c/,C:/, $(SOURCES_DOT))
$(info SOURCES_DOT= $(SOURCES_DOT) )
ART_SVG := $(subst doti,svg, $(SOURCES_DOT))
ART_PDF := $(subst doti,pdf, $(SOURCES_DOT))
OPT +=
DOT_OPT +=-Tsvg
#DOT_OPT +=-L10
#DOT_OPT +=-v
#LAYOUT_ENGINE = -Kneato
#LAYOUT_ENGINE = -Kfdp
#LAYOUT_ENGINE = -Ksfdp
#LAYOUT_ENGINE = -Ktwopi
#LAYOUT_ENGINE = -Kosage
#LAYOUT_ENGINE = -Kpatchwork
LAYOUT_ENGINE = -Kdot
preproc:$(SOURCES_DOT)
$(info Preproc...)
cpp $(SOURCES_DOT) $(OPT) -E -o $(SOURCES_DOT_RES)
generate_pdf: preproc
$(info route graph...)
$(CC_DOT) -V
$(CC_DOT) -Tpdf $(LAYOUT_ENGINE) $(SOURCES_DOT_RES) -o $(ART_PDF)
generate_svg: preproc
$(info route graph...)
$(CC_DOT) -V
$(CC_DOT) $(DOT_OPT) $(SOURCES_DOT_RES) -o $(ART_SVG)
print_svg: generate_svg generate_pdf
$(info print_svg)
$(RENDER) -open $(ART_SVG)
$(RENDER) -open $(ART_PDF)
all: print_svg
$(info All)
clean:
$(info clean)
rm ToolChain_nRF5340_res.svg
rm $(SOURCES_DOT_RES)
#$(ART_SVG):$(ART_SVG)
Для любителей системы сборки ninja я тоже накропал build.ninja скрипт
cflags = -Tsvg
cur_dir = C:\projects\code_base_workspace\code_base_firmware\docs\toolchain_nRF5340\
RENDER="C:/Program Files/Google/Chrome/Application/chrome.exe"
rule preproc
command = cpp $in -E -o $out
rule generate_svg
command = dot $cflags $in -o $out
rule print_in_browse
command = $RENDER -open $cur_dir/$in
rule clean_temp
command = rm *_generated.svg
command = rm *_res.dot
rule svg2pdf
command = dot.exe -Tpdf $in -o $out
build clean: clean_temp
build ToolChain_nRF5340_res.dot: preproc ToolChain_nRF5340.doti
build ToolChain_nRF5340_generated.svg: generate_svg ToolChain_nRF5340_res.dot
build ToolChain_nRF5340_generated.pdf: svg2pdf ToolChain_nRF5340_res.dot
build make_svg: print_in_browse ToolChain_nRF5340_generated.svg
build make_pdf: print_in_browse ToolChain_nRF5340_generated.pdf
default make_pdf
В результате мы собрали вот такую замечательную блок схемку ToolChain для системы сборки Zephyr.
![Автоматически сгенерированная схема ToolChain(а) Автоматически сгенерированная схема ToolChain(а)](https://habrastorage.org/getpro/habr/upload_files/589/90c/a40/58990ca408e801f63d369d8c1b1bc5b9.png)
Успех! Теперь все как на ладони. Причем при просмотре *.svg из браузера даже Ctrl+F поиск есть! Супер!
Буквально пара слов про Zephyr. Видно, что Zephyr собирает проекты в два супер этапа. Сначала Zephyr собирает конфигурацию. Результат сборки конфигурации это Makefile или build.ninja плюс несколько заголовочных файлов *.h, затем собирают сами артефакты на основе собранной ранее конфигурации. На схеме все прекрасно видно. Рулит всем внутри фактически CMake. Но есть Python скрипты west, которые запускают CMake.
Вот полный *.dot код с выхода препроцессора для тех, кто хочет изучить схему под увеличением
Hidden text
digraph graphname {
rankdir=TB;
splines=ortho;
Monitor [label="Monitor"] [shape = box][fillcolor = grey][style="filled"]
Programmator [label="Programmator"] [shape = box][fillcolor = grey][style="filled"]
TargetMcu [label="nRF5340 (ARM Cortex-M33 2x Core)"] [shape = box][fillcolor = grey][style="filled"]
HOST_USB [label="USB"] [shape = box][fillcolor = grey][style="filled"]
USB_CONNECTOR_BOARD [label="USB"] [shape = box][fillcolor = grey][style="filled"]
HostCpu [label="X86 AMD64"] [shape = box][fillcolor = grey][style="filled"]
HostCpu->HOST_USB
HOST_USB->USB_CONNECTOR_BOARD[label="USB"]
USB_CONNECTOR_BOARD->Programmator[label="USB"]
Programmator->TargetMcu[label="SWD"]
subgraph cluster_NetTop {
style=filled;
color=aliceblue;
label = "NetTop (WorkStation Computer)";
HostCpu
HOST_USB
subgraph cluster_Windows10 {
style=filled;
color=lightblue;
label = "Windows10";
west [label="west.py"] [shape = box][style="filled"] [fillcolor = plum1]
scripts_kconfig [label="zephyr/scripts/kconfig.py"] [shape = box][style="filled"] [fillcolor = plum1]
menuconfig [label="menuconfig.py"] [shape = box][style="filled"] [fillcolor = plum1]
gen_defines_py [label="zephyr/scripts/dts/gen_defines.py"] [shape = box][style="filled"] [fillcolor = plum1]
buildprog [label="buildprog.py"][shape = box][style="filled"] [fillcolor = plum1]
guiconfig [label="guiconfig.py"] [shape = box][style="filled"] [fillcolor = plum1]
clang_format [label="clang-format.exe"] [shape = box][style="filled"]
eclipse [label="Eclipse.exe"] [shape = box][style="filled"]
eclipsec [label="eclipsec.exe"] [shape = box][style="filled"]
bash [label="bash.exe"] [shape = box][style="filled"]
hexdump [label="hexdump.exe"] [shape = box][style="filled"]
browser [label="chrome.exe"] [shape = box][style="filled"]
inkscape [label="Inkscape.exe"] [shape = box][style="filled"]
nrfjprog [label="nrfjprog.exe"] [shape = box][style="filled"]
Cppcheck [label="Cppcheck.exe"] [shape = box][style="filled"]
fdtdump [label="fdtdump.exe"] [shape = box][style="filled"]
dtc [label="dtc"] [shape = box][style="filled"]
cpp_ld[label="cpp.exe"] [shape = box][style="filled"]
jenkins [label="jenkins.exe"][shape = box][style="filled"]
cpp [label="cpp.exe"][shape = box][style="filled"]
chocolatey [label="chocolatey.exe"][shape = box][style="filled"]
git [label="git.exe"][shape = box][style="filled"]
JLinkGDBServer [label="JLinkGDBServer.exe"][shape = box][style="filled"]
cpp_dot [label="cpp.exe"] [shape = box][style="filled"]
cpp_3 [label="cpp.exe (preproc)"] [shape = box][style="filled"]
compiler [label="arm-zephyr-eabi-gcc.exe (ARM Compiler)"] [shape = box][style="filled"]
NotePadPp [label="Notepad++.exe"] [shape = box][style="filled"]
cmd [label="cmd.exe"] [shape = box][style="filled"]
GDB [label="gdb.exe"] [shape = box][style="filled"]
cMake [label="cmake.exe"] [shape = box][style="filled"]
GN [label="gn.exe"] [shape = box][style="filled"]
nrfjprog [label="nrfjprog.exe"] [shape = box][style="filled"]
Python [label="Python.exe"] [shape = box][style="filled"]
make [label="make.exe"] [shape = box][style="filled"]
ninja [label="ninja.exe"] [shape = box][style="filled"]
objcopy [label="objcopy.exe"] [shape = box][style="filled"] [fillcolor = deepskyblue]
linker [label="ld.exe (linker)"] [shape = box][style="filled"] [fillcolor = deepskyblue]
as [label="as.exe"] [shape = box][style="filled"] [fillcolor = deepskyblue]
nm [label="nm.exe"] [shape = box][style="filled"] [fillcolor = deepskyblue]
ar [label="ar.exe"] [shape = box][style="filled"] [fillcolor = deepskyblue]
readelf [label="readelf.exe"] [shape = box][style="filled"] [fillcolor = deepskyblue]
gprof [label="gprof.exe"] [shape = box][style="filled"] [fillcolor = deepskyblue]
addr2line [label="addr2line.exe"] [shape = box][style="filled"] [fillcolor = deepskyblue]
dot [label="dot.exe"][shape = box][style="filled"]
dtsi[label="*.dtsi"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
DotConf[label="*.conf (Kernel configuration)"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
bat_file[label="*.bat"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
CMakeLists [label="CMakeLists.txt "] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
sh_file[label="*.sh"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
Kconfig_defaults[label="Kconfig.defaults"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
ld_file[label="*.ld"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
mk_file[label="*.mk"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
overlay_file[label="*.overlay"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
h_file[label="*.h"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
c_file[label="*.c"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
dot_file[label="*.dot"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
doti_file[label="*.doti"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
yaml[label="*.yaml"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
Kconfig [label="Kconfig"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
dts[label="*.dts"] [shape = note][fillcolor = gold][style="filled"] [style="filled"][fillcolor = green]
devicetree_h[label="devicetree.h"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
devicetree_fixups_h[label="devicetree_fixups.h"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
devicetree_unfixed_h[label="devicetree_unfixed.h"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
zephyr_dts_pre[label="zephyr.dts.pre"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
cproject [label=".cproject "] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
project [label=".project (description file)"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
Kconfig_zephyr[label="Kconfig.zephyr"] [shape = note][fillcolor = gold][style="filled"]
txt_file[label="*.txt"] [shape = note][fillcolor = gold][style="filled"]
CMakeCache_txt [label="CMakeCache.txt"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
map_file[label="*.map"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
hex_file[label="*.hex"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
obj_file[label="*.o"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin] [fillcolor = turquoise1]
a_file[label="*.a"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin] [fillcolor = turquoise1]
elf_file[label="*.elf"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin] [fillcolor = turquoise1]
dtb_file[label="*.dtb"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin] [fillcolor = turquoise1]
bin_file[label="*.bin"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin] [fillcolor = turquoise1]
build_ninja [label="build.ninja"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
json_file[label="*.json"] [shape = note][fillcolor = gold][style="filled"]
svg_file[label="*.svg "] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
west_yml[label="west.yml (manifest file)"] [shape = note][fillcolor = gold][style="filled"]
MakeFile[label="Makefile"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
devicetree_generated_h[label="devicetree_generated.h"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
zephyr_dts[label="zephyr.dts"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
autoconfig_h [label="autoconfig.h"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
s_file [label="*.S"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
gn_file [label="BUILD.gn"] [shape = note][fillcolor = gold][style="filled"]
cmd_file [label="*.cmd"] [shape = note][fillcolor = gold][style="filled"]
pp_file [label="*.pp"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
DotConfig [label=".config"] [shape = note][fillcolor = gold][style="filled"] [fillcolor = moccasin]
cmake_file[label="*.cmake"] [shape = note][fillcolor = gold][style="filled"]
defconfig_file[label="*.defconfig"] [shape = note][fillcolor = gold][style="filled"]
NotePadPp->bat_file[label="*.bat"][dir="both"]
NotePadPp->doti_file[label="*.doti"] [dir="both"]
NotePadPp->sh_file[label="*.sh"][dir="both"]
NotePadPp->mk_file[label="*.mk"][dir="both"]
NotePadPp->c_file[label="*.c"][dir="both"]
NotePadPp->h_file[label="*.h"][dir="both"]
bat_file->cmd[label="*.bat"]
sh_file->bash[label="*.sh"]
subgraph cluster_JVM {
style=filled;
color=lightgreen;
label = "JVM";
jenkins->bash
eclipsec
cproject->eclipse[label=".cproject"][dir="both"]
project->eclipse[label=".project"][dir="both"]
}
subgraph cluster_BuildConfig {
style=filled;
color=khaki1;
label = "Build Configuration (buildsystem)";
bash->buildprog
cmd->buildprog
Python->buildprog
json_file->buildprog [label="*.json"]
west_yml->west[label="west.yml"]
Python->west
buildprog->west[label="?"]
dtsi->cpp[label="*.dtsi"]
dts->cpp[label="*.dts"]
overlay_file->cpp[label="*.overlay"]
cpp->zephyr_dts_pre[label="zephyr.dts.pre"]
yaml->gen_defines_py[label="*.yaml"]
zephyr_dts_pre->gen_defines_py[label="zephyr.dts.pre"]
zephyr_dts->dtc[label="zephyr.dts"]
dtc->dtb_file[label="*.dtb"]
CMakeLists->cMake[label="CMakeLists.txt"]
west->cMake
cMake->gen_defines_py
gen_defines_py->zephyr_dts[label="zephyr.dts"]
gen_defines_py->devicetree_unfixed_h[label="devicetree_unfixed.h"]
gen_defines_py->devicetree_generated_h[label="devicetree_generated.h"]
cMake->CMakeCache_txt[label="CMakeCache.txt"] [dir="both"]
gn_file->GN
GN->build_ninja[label="build.ninja"]
cMake->build_ninja[label="build.ninja"]
cMake->MakeFile[label="MakeFile"]
west->menuconfig [label="build -t"]
Kconfig_defaults->Kconfig[label="Kconfig.defaults"]
Kconfig->Kconfig_zephyr
west->guiconfig[label="build -t"]
Kconfig->scripts_kconfig[label="Kconfig"]
DotConf->scripts_kconfig[label="*.conf"]
cMake->scripts_kconfig
scripts_kconfig->autoconfig_h[label="autoconfig.h"]
scripts_kconfig->DotConfig[label="*.config"]
DotConfig->menuconfig[label="*.config"][dir="both"]
DotConfig->guiconfig[label="*.config"][dir="both"]
DotConfig->cMake[label="*.config"]
autoconfig_h->cMake[label="autoconfig.h"]
devicetree_unfixed_h->devicetree_h[label="devicetree_unfixed.h"]
devicetree_fixups_h->devicetree_h[label="devicetree_fixups.h"]
dtb_file->fdtdump[label="*.dtb"]
}
ld_file->git[label="*.ld"][dir="both"]
sh_file->git[label="*.sh"][dir="both"]
h_file->git[label="*.h"][dir="both"]
c_file->git[label="*.c"][dir="both"]
mk_file->git[label="*.mk"][dir="both"]
doti_file->git[label="*.doti"][dir="both"]
cproject->git[label=".cproject"][dir="both"]
MakeFile->git[label="Makefile"][dir="both"]
project->git[label=".project"][dir="both"]
c_file->eclipse[label="*.c "]
h_file->eclipse[label="*.h"]
eclipse->c_file[label="*.c "]
eclipse->h_file[label="*.h"]
eclipse->MakeFile[dir="both"][label="Makefile"]
eclipse->mk_file[dir="both"][label="*.mk"]
cMake-> project
cMake-> cproject
subgraph cluster_BuildArtefact {
style=filled;
color=gray100;
label = "Build Artefact";
build_ninja->ninja[label="Makefile"]
ninja->cpp_3
h_file->cpp_3
c_file->cpp_3
autoconfig_h->cpp_3[label="autoconfig.h"]
devicetree_generated_h->cpp_3
pp_file->compiler
compiler->s_file [label="*.S"]
s_file->as [label="*.S"]
compiler->ar
as->obj_file [label="*.obj"]
obj_file->ar[label="*.o"]
ar->a_file[label="*.a"]
obj_file->nm[label="*.o"]
ld_file->cpp_ld[label="*.ld"]
cpp_ld->cmd_file[label="*.cmd"]
obj_file->linker [label="*.obj"]
cmd_file->linker[label="*.cmd"]
a_file->linker[label="*.a"]
linker->elf_file[label="*.elf"]
linker->map_file[label="*.map"]
elf_file->addr2line[label="*.elf"]
addr2line->eclipse[label=".txt"]
elf_file -> objcopy
objcopy->bin_file
objcopy->hex_file
elf_file->readelf[label="*.elf"]
elf_file->GDB[label="*.elf"]
GDB-> JLinkGDBServer[dir="both"][label="port:2331"]
bin_file->hexdump[label="*.bin"]
hexdump->txt_file[label="*.txt"]
mk_file->make[label="*.mk"]
MakeFile->make[label="MakeFile"]
make->cpp_3
cpp_3 -> pp_file
hex_file->nrfjprog
}
subgraph cluster_BuildDoc {
style=filled;
color=beige;
label = "Build Documentation";
doti_file->cpp_dot
cpp_dot->dot_file
dot_file->dot
dot->svg_file[label="*.svg"]
svg_file->browser[label="*.svg"]
svg_file->inkscape[label="*.svg"]
}
clang_format->c_file[label="*.c"][dir="both"]
clang_format->h_file[label="*.h"][dir="both"]
h_file->Cppcheck[label="*.h"]
c_file->Cppcheck[label="*.c"]
browser->jenkins[label="8080"]
}
}
eclipse->Monitor
nrfjprog->HOST_USB
JLinkGDBServer->HOST_USB
subgraph cluster_Board {
style=filled;
color=lightblue;
label = "Board";
USB_CONNECTOR_BOARD
Programmator
TargetMcu
}
}
ShowRoom схем ToolChain(ов)
Вот классическая схема ToolChain для сборки прошивок под микроконтроллер nrf5340.
![](https://habrastorage.org/getpro/habr/upload_files/4a2/eb4/e14/4a2eb4e141fc752b1f4af93d020e3e2c.jpg)
А это схема ToolChain(а) при разработке топологии для электронной платы
![](https://habrastorage.org/getpro/habr/upload_files/c48/c06/f99/c48c06f99429bdb29904ee3ac6310854.png)
Это схема метаморфоза файлов для черчения
![](https://habrastorage.org/getpro/habr/upload_files/340/b67/5f2/340b675f23e26ce3e2456f00ec1dd8d6.png)
Вывод
Как видите синергия препроцессора cpp и языка разметки Graphviz может оказаться очень полезна и эффективна в разработке софта и всяческой документации. Это позволяет высвободить тонну времени от ручной перерисовки. Можно также из Graphviz генерировать архитектуры систем на чипе SoC, схемы электрических цепочек, графы задач из task tracker(а), нейронные сети, конечные автоматы, схемы метро. Да всё, что только душе угодно, что имеет графо образную природу.
Язык Graphviz настолько хорош и универсален, что его следовало бы включить в университетскую программу обучения в технических факультетах в качестве одной лабораторной работы по компьютерным технологиям.
Особенно советую обратить внимание на связку сpp.exe/dot.exe/make.exe тем кто работает техническими писателями и схемотехниками. Это тот самый случай, когда программирование на Graphviz может принести пользу.
Ссылки про язык Dot
https://habr.com/ru/post/682346/
https://habr.com/ru/post/499170/
https://habr.com/ru/post/337078/