From 9de1f19388568be00a5470a0937169e66c0ec23e Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Tue, 28 Jul 2026 10:54:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B8=B8=E8=A7=84=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vsg_cesium/current_compiler.cmake | 3 + .../triplets/x64-windows-static-md.cmake | 5 + Doxygen/Doxyfile.in | 40 +++ Doxygen/export.cmake | 1 + Graphviz/Cmake_Target_Graph.ps1.in | 64 ++++ Graphviz/Cmake_Target_Graph.sh.in | 52 +++ Graphviz/Graphviz_Render.ps1.in | 13 + Graphviz/Graphviz_Render.sh.in | 12 + Graphviz/Project_Graphs.ps1.in | 339 ++++++++++++++++++ Graphviz/Project_Graphs.sh.in | 156 ++++++++ Graphviz/export.cmake | 1 + 11 files changed, 686 insertions(+) create mode 100644 0_cmake_library/register/generated/vsg_cesium/current_compiler.cmake create mode 100644 0_cmake_library/register/generated/vsg_cesium/triplets/x64-windows-static-md.cmake create mode 100644 Doxygen/Doxyfile.in create mode 100644 Doxygen/export.cmake create mode 100644 Graphviz/Cmake_Target_Graph.ps1.in create mode 100644 Graphviz/Cmake_Target_Graph.sh.in create mode 100644 Graphviz/Graphviz_Render.ps1.in create mode 100644 Graphviz/Graphviz_Render.sh.in create mode 100644 Graphviz/Project_Graphs.ps1.in create mode 100644 Graphviz/Project_Graphs.sh.in create mode 100644 Graphviz/export.cmake diff --git a/0_cmake_library/register/generated/vsg_cesium/current_compiler.cmake b/0_cmake_library/register/generated/vsg_cesium/current_compiler.cmake new file mode 100644 index 0000000..1617708 --- /dev/null +++ b/0_cmake_library/register/generated/vsg_cesium/current_compiler.cmake @@ -0,0 +1,3 @@ +set(CMAKE_C_COMPILER [[C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.bat]] CACHE FILEPATH "" FORCE) +set(CMAKE_CXX_COMPILER [[C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.bat]] CACHE FILEPATH "" FORCE) +set(CMAKE_RC_COMPILER [[C:/Program Files (x86)/Windows Kits/10/bin/10.0.26100.0/x64/rc.exe]] CACHE FILEPATH "" FORCE) diff --git a/0_cmake_library/register/generated/vsg_cesium/triplets/x64-windows-static-md.cmake b/0_cmake_library/register/generated/vsg_cesium/triplets/x64-windows-static-md.cmake new file mode 100644 index 0000000..c577f81 --- /dev/null +++ b/0_cmake_library/register/generated/vsg_cesium/triplets/x64-windows-static-md.cmake @@ -0,0 +1,5 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE [[D:/ae/proj/git/Radio/third_party/build_infra/0_cmake_library/register/generated/vsg_cesium/current_compiler.cmake]]) +set(VCPKG_VISUAL_STUDIO_PATH [[C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise]]) diff --git a/Doxygen/Doxyfile.in b/Doxygen/Doxyfile.in new file mode 100644 index 0000000..81d45e6 --- /dev/null +++ b/Doxygen/Doxyfile.in @@ -0,0 +1,40 @@ +PROJECT_NAME = "@ARG_PROJECT_NAME@" +OUTPUT_DIRECTORY = "@ARG_OUTPUT_DIR@" +INPUT = @doxygen_input@ +EXCLUDE = @doxygen_exclude@ +FILE_PATTERNS = @doxygen_file_patterns@ +RECURSIVE = YES +GENERATE_HTML = YES +GENERATE_LATEX = NO +GENERATE_XML = YES +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_AS_ERROR = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = YES +OPTIMIZE_OUTPUT_FOR_C = NO +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +PREDEFINED = @doxygen_predefined@ +HAVE_DOT = YES +DOT_PATH = "@dot_dir@" +DOT_IMAGE_FORMAT = svg +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +CALLER_GRAPH = YES +DIRECTORY_GRAPH = YES +UML_LOOK = NO +INTERACTIVE_SVG = YES +MAX_DOT_GRAPH_DEPTH = 0 diff --git a/Doxygen/export.cmake b/Doxygen/export.cmake new file mode 100644 index 0000000..44e4407 --- /dev/null +++ b/Doxygen/export.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/main.cmake) diff --git a/Graphviz/Cmake_Target_Graph.ps1.in b/Graphviz/Cmake_Target_Graph.ps1.in new file mode 100644 index 0000000..8f3d1f5 --- /dev/null +++ b/Graphviz/Cmake_Target_Graph.ps1.in @@ -0,0 +1,64 @@ +$ErrorActionPreference = 'Stop' +$targets = @PSC_TARGETS@ +$edges = @PSC_TARGET_EDGES@ +$outputDir = '@PSC_OUTPUT_DIR@' +$format = '@PSC_FORMAT@' +$dotExe = '@PSC_DOT_EXECUTABLE@' +New-Item -ItemType Directory -Force -Path $outputDir | Out-Null +function Convert-To_Dot_Text([string]$text) { + return $text.Replace('"', '\"') +} +$lines = [System.Collections.Generic.List[string]]::new() +$lines.Add('digraph "radio cmake_targets" {') +$lines.Add('rankdir=LR;') +$lines.Add('splines=ortho;') +$lines.Add('concentrate=true;') +$lines.Add('forcelabels=true;') +$lines.Add('graph [fontname="Consolas", label="radio cmake_targets", labelloc=t, fontsize=18];') +$lines.Add('node [shape=box, style="rounded,filled", fontname="Consolas", fontsize=10];') +$lines.Add('edge [fontname="Consolas", fontsize=9];') +foreach ($target in $targets) { + $safe = Convert-To_Dot_Text $target + $lines.Add('"' + $safe + '" [label="' + $safe + '", tooltip="' + $safe + '", fillcolor="#dcfce7"];') +} +foreach ($edge in $edges) { + $parts = $edge.Split('|') + if ($parts.Count -eq 2) { + $left = Convert-To_Dot_Text $parts[0] + $right = Convert-To_Dot_Text $parts[1] + $lines.Add('"' + $left + '" -> "' + $right + '" [xlabel="links"];') + } +} +$lines.Add('subgraph cluster_legend {') +$lines.Add('label="legend";') +$lines.Add('style="rounded,dashed";') +$lines.Add('"legend_target" [label="cmake target", fillcolor="#dcfce7"];') +$lines.Add('"legend_edge" [label="edge = target_link_libraries / target dependency", fillcolor="#f8fafc"];') +$lines.Add('}') +$lines.Add('}') +$dotFile = Join-Path $outputDir 'radio_cmake_targets.dot' +$imageFile = Join-Path $outputDir ('radio_cmake_targets.' + $format) +Set-Content -LiteralPath $dotFile -Value $lines -Encoding UTF8 +& $dotExe ('-T' + $format) $dotFile '-o' $imageFile +if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE +} +$items = @( + 'radio_directory_tree', + 'radio_module_dependency', + 'radio_cmake_targets', + 'radio_include_dependency', + 'radio_render_architecture' +) +$html = [System.Collections.Generic.List[string]]::new() +$html.Add('Radio Graphviz

Radio Graphviz

') +Set-Content -LiteralPath (Join-Path $outputDir 'index.html') -Value $html -Encoding UTF8 diff --git a/Graphviz/Cmake_Target_Graph.sh.in b/Graphviz/Cmake_Target_Graph.sh.in new file mode 100644 index 0000000..307cb9d --- /dev/null +++ b/Graphviz/Cmake_Target_Graph.sh.in @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -euo pipefail +targets=(@PSC_TARGETS_SH@) +edges=(@PSC_TARGET_EDGES_SH@) +output_dir='@PSC_OUTPUT_DIR@' +format='@PSC_FORMAT@' +dot_exe='@PSC_DOT_EXECUTABLE@' +mkdir -p "$output_dir" +dot_file="$output_dir/radio_cmake_targets.dot" +image_file="$output_dir/radio_cmake_targets.$format" +{ + echo 'digraph "radio cmake_targets" {' + echo 'rankdir=LR;' + echo 'splines=ortho;' + echo 'concentrate=true;' + echo 'forcelabels=true;' + echo 'graph [fontname="Consolas", label="radio cmake_targets", labelloc=t, fontsize=18];' + echo 'node [shape=box, style="rounded,filled", fontname="Consolas", fontsize=10];' + echo 'edge [fontname="Consolas", fontsize=9];' + for target in "${targets[@]}"; do + safe=${target//\"/\\\"} + echo "\"$safe\" [label=\"$safe\", tooltip=\"$safe\", fillcolor=\"#dcfce7\"];" + done + for edge in "${edges[@]}"; do + left=${edge%%|*} + right=${edge#*|} + left=${left//\"/\\\"} + right=${right//\"/\\\"} + echo "\"$left\" -> \"$right\" [xlabel=\"links\"];" + done + echo 'subgraph cluster_legend {' + echo 'label="legend";' + echo 'style="rounded,dashed";' + echo '"legend_target" [label="cmake target", fillcolor="#dcfce7"];' + echo '"legend_edge" [label="edge = target_link_libraries / target dependency", fillcolor="#f8fafc"];' + echo '}' + echo '}' +} > "$dot_file" +"$dot_exe" "-T$format" "$dot_file" -o "$image_file" +items=(radio_directory_tree radio_module_dependency radio_cmake_targets radio_include_dependency radio_render_architecture) +{ + echo 'Radio Graphviz

Radio Graphviz

' +} > "$output_dir/index.html" diff --git a/Graphviz/Graphviz_Render.ps1.in b/Graphviz/Graphviz_Render.ps1.in new file mode 100644 index 0000000..3dab933 --- /dev/null +++ b/Graphviz/Graphviz_Render.ps1.in @@ -0,0 +1,13 @@ +$ErrorActionPreference = 'Stop' +$inputs = @PSC_INPUT_FILES@ +$outputDir = '@PSC_OUTPUT_DIR@' +$format = '@PSC_FORMAT@' +$dotExe = '@PSC_DOT_EXECUTABLE@' +New-Item -ItemType Directory -Force -Path $outputDir | Out-Null +foreach ($inputFile in $inputs) { + $name = [System.IO.Path]::GetFileNameWithoutExtension($inputFile) + & $dotExe ('-T' + $format) $inputFile '-o' (Join-Path $outputDir ($name + '.' + $format)) + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } +} diff --git a/Graphviz/Graphviz_Render.sh.in b/Graphviz/Graphviz_Render.sh.in new file mode 100644 index 0000000..e4038af --- /dev/null +++ b/Graphviz/Graphviz_Render.sh.in @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +inputs=(@PSC_INPUT_FILES_SH@) +output_dir='@PSC_OUTPUT_DIR@' +format='@PSC_FORMAT@' +dot_exe='@PSC_DOT_EXECUTABLE@' +mkdir -p "$output_dir" +for input_file in "${inputs[@]}"; do + name=$(basename "$input_file") + name=${name%.*} + "$dot_exe" "-T$format" "$input_file" -o "$output_dir/$name.$format" +done diff --git a/Graphviz/Project_Graphs.ps1.in b/Graphviz/Project_Graphs.ps1.in new file mode 100644 index 0000000..6e028a2 --- /dev/null +++ b/Graphviz/Project_Graphs.ps1.in @@ -0,0 +1,339 @@ +$ErrorActionPreference = 'Stop' +$inputs = @PSC_INPUT_DIRS@ +$excludeDirs = @PSC_EXCLUDE_DIRS@ +$outputDir = '@PSC_OUTPUT_DIR@' +$format = '@PSC_FORMAT@' +$dotExe = '@PSC_DOT_EXECUTABLE@' +$maxDepth = @PSC_MAX_DEPTH@ +$collapseThreshold = @PSC_COLLAPSE_THRESHOLD@ +$excludeThirdParty = @PSC_EXCLUDE_THIRD_PARTY@ +New-Item -ItemType Directory -Force -Path $outputDir | Out-Null +function Convert-To_Generic_Path([string]$path) { + return ([System.IO.Path]::GetFullPath($path)).Replace('\', '/') +} +function Convert-To_Dot_Text([string]$text) { + return $text.Replace('\', '/').Replace('"', '\"') +} +function Get-Root_Name([string]$root) { + $path = Convert-To_Generic_Path $root + if ($path -match '/module/radio$') { + return 'radio' + } + if ($path -match '/CPP_Core/Core$') { + return 'CPP_Core' + } + if ($path -match '/YSGraphic_Core$') { + return 'YSGraphic_Core' + } + return [System.IO.Path]::GetFileName($path) +} +function Get-Relative_Path([string]$root, [string]$path) { + $rootPath = Convert-To_Generic_Path $root + $fullPath = Convert-To_Generic_Path $path + if ($fullPath.StartsWith($rootPath)) { + return $fullPath.Substring($rootPath.Length).TrimStart('/') + } + return $fullPath +} +function Test-Excluded_Path([string]$path) { + $fullPath = Convert-To_Generic_Path $path + if ($excludeThirdParty -and $fullPath.Contains('/third_party/')) { + return $true + } + foreach ($excludeDir in $excludeDirs) { + if ($excludeDir.Length -eq 0) { + continue + } + $excludePath = Convert-To_Generic_Path $excludeDir + if ($fullPath.StartsWith($excludePath)) { + return $true + } + } + return $false +} +function Get-Source_Files([string[]]$roots) { + $extensions = @('.h', '.hpp', '.hh', '.cpp', '.cxx', '.cc') + $files = [System.Collections.Generic.List[object]]::new() + foreach ($root in $roots) { + if (!(Test-Path -LiteralPath $root)) { + continue + } + Get-ChildItem -LiteralPath $root -Recurse -File | Where-Object { + $extensions -contains $_.Extension.ToLowerInvariant() -and !(Test-Excluded_Path $_.FullName) + } | ForEach-Object { + $files.Add($_) + } + } + return $files +} +function Invoke-Dot([string]$name, [System.Collections.Generic.List[string]]$lines) { + $dotFile = Join-Path $outputDir ($name + '.dot') + $imageFile = Join-Path $outputDir ($name + '.' + $format) + Set-Content -LiteralPath $dotFile -Value $lines -Encoding UTF8 + & $dotExe ('-T' + $format) $dotFile '-o' $imageFile + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } +} +function Write-Graphviz_Index() { + $items = @( + 'radio_directory_tree', + 'radio_module_dependency', + 'radio_cmake_targets', + 'radio_include_dependency', + 'radio_render_architecture' + ) + $html = [System.Collections.Generic.List[string]]::new() + $html.Add('Radio Graphviz

Radio Graphviz

') + Set-Content -LiteralPath (Join-Path $outputDir 'index.html') -Value $html -Encoding UTF8 +} +function Add-Header([System.Collections.Generic.List[string]]$lines, [string]$title) { + $lines.Add('digraph "' + (Convert-To_Dot_Text $title) + '" {') + $lines.Add('rankdir=LR;') + $lines.Add('splines=ortho;') + $lines.Add('concentrate=true;') + $lines.Add('forcelabels=true;') + $lines.Add('graph [fontname="Consolas", label="' + (Convert-To_Dot_Text $title) + '", labelloc=t, fontsize=18];') + $lines.Add('node [shape=box, style="rounded,filled", fontname="Consolas", fontsize=10];') + $lines.Add('edge [fontname="Consolas", fontsize=9];') +} +function Add-Legend([System.Collections.Generic.List[string]]$lines, [string]$mode) { + $lines.Add('subgraph cluster_legend {') + $lines.Add('label="legend";') + $lines.Add('style="rounded,dashed";') + $lines.Add('"legend_module" [label="module/folder", fillcolor="#dbeafe", tooltip="聚合模块或目录节点"];') + $lines.Add('"legend_target" [label="cmake target", fillcolor="#dcfce7", tooltip="CMake target 节点"];') + $lines.Add('"legend_buffer" [label="buffer/cache", fillcolor="#fef3c7", tooltip="缓冲区或长期缓存"];') + $lines.Add('"legend_runtime" [label="runtime", fillcolor="#fee2e2", tooltip="运行期任务或 Qt 绘制入口"];') + if ($mode -eq 'include') { + $lines.Add('"legend_edge" [label="include:N node = include count", fillcolor="#f8fafc"];') + } else { + $lines.Add('"legend_edge" [label="edge label = relation", fillcolor="#f8fafc"];') + } + $lines.Add('}') +} +function Get-Immediate_Source_Count([string]$dir) { + $extensions = @('.h', '.hpp', '.hh', '.cpp', '.cxx', '.cc') + return @(Get-ChildItem -LiteralPath $dir -File | Where-Object { + $extensions -contains $_.Extension.ToLowerInvariant() + }).Count +} +function Get-Visible_Directories([string]$dir) { + return @(Get-ChildItem -LiteralPath $dir -Directory | Where-Object { + !(Test-Excluded_Path $_.FullName) + }) +} +function Add-Directory_Node([System.Collections.Generic.List[string]]$lines, [string]$root, [string]$dir, [int]$depth, [string]$parentId) { + if ($depth -gt $maxDepth -or (Test-Excluded_Path $dir)) { + return + } + $rootName = Get-Root_Name $root + $relative = Get-Relative_Path $root $dir + $name = if ($relative.Length -eq 0) { $rootName } else { [System.IO.Path]::GetFileName($dir) } + $idPath = if ($relative.Length -eq 0) { $rootName } else { $rootName + '/' + $relative } + $id = 'dir:' + $idPath + $fileCount = Get-Immediate_Source_Count $dir + $children = Get-Visible_Directories $dir + $label = (Convert-To_Dot_Text $name) + '\nfiles: ' + $fileCount + '\ndirs: ' + $children.Count + $tooltip = Convert-To_Dot_Text $idPath + $lines.Add('"' + $id + '" [label="' + $label + '", tooltip="' + $tooltip + '", fillcolor="#dbeafe"];') + if ($parentId.Length -gt 0) { + $lines.Add('"' + $parentId + '" -> "' + $id + '" [xlabel="contains"];') + } + if ($depth -eq $maxDepth) { + return + } + if ($fileCount -gt $collapseThreshold -and $depth -gt 0) { + return + } + foreach ($child in $children) { + Add-Directory_Node $lines $root $child.FullName ($depth + 1) $id + } +} +function New-Directory_Tree_Graph() { + $lines = [System.Collections.Generic.List[string]]::new() + Add-Header $lines 'radio directory_tree' + foreach ($root in $inputs) { + if (!(Test-Path -LiteralPath $root)) { + continue + } + $rootName = Get-Root_Name $root + $clusterName = $rootName.Replace('-', '_').Replace('/', '_') + $lines.Add('subgraph "cluster_' + $clusterName + '" {') + $lines.Add('label="' + (Convert-To_Dot_Text $rootName) + '";') + $lines.Add('style="rounded";') + Add-Directory_Node $lines $root $root 0 '' + $lines.Add('}') + } + Add-Legend $lines 'directory' + $lines.Add('}') + Invoke-Dot 'radio_directory_tree' $lines +} +function Get-Root_For_File([string]$path) { + $fullPath = Convert-To_Generic_Path $path + foreach ($root in $inputs) { + $rootPath = Convert-To_Generic_Path $root + if ($fullPath.StartsWith($rootPath)) { + return $root + } + } + return '' +} +function Get-Module_Key([string]$path, [int]$depth) { + $root = Get-Root_For_File $path + if ($root.Length -eq 0) { + return '' + } + $rootName = Get-Root_Name $root + $relative = Get-Relative_Path $root $path + $parts = @($relative.Split('/') | Where-Object { $_.Length -gt 0 }) + if ($rootName -eq 'radio') { + $base = 'module/radio' + } elseif ($rootName -eq 'CPP_Core') { + $base = 'third_party/CPP_Core/Core' + } elseif ($rootName -eq 'YSGraphic_Core') { + $base = 'third_party/Graphic_Core/YSGraphic_Core' + } else { + $base = $rootName + } + if ($parts.Count -eq 0 -or $depth -eq 0) { + return $base + } + $take = [Math]::Min($depth, $parts.Count) + return $base + '/' + (($parts | Select-Object -First $take) -join '/') +} +function Test-Ignored_Include([string]$includeText) { + $text = $includeText.Trim() + if ($text -match '^(Q[A-ZA-z0-9_]*|Qt[A-ZA-z0-9_/]*|QObject|QWidget|QString|QVector|QMap|QList)$') { + return $true + } + if ($text -match '^(array|atomic|chrono|cmath|cstdint|cstdio|cstdlib|cstring|filesystem|functional|limits|map|memory|mutex|optional|set|span|string|string_view|thread|tuple|type_traits|unordered_map|utility|vector)$') { + return $true + } + if ($text -match '^(boost/|asio|windows\.h|winsock|d3d|GL/)') { + return $true + } + return $false +} +function Resolve-Include_Path([string]$includeText, [hashtable]$suffixMap, [hashtable]$nameMap) { + $key = $includeText.Replace('\', '/').ToLowerInvariant() + if ($suffixMap.ContainsKey($key)) { + return $suffixMap[$key] + } + $leaf = [System.IO.Path]::GetFileName($key) + if ($nameMap.ContainsKey($leaf)) { + return $nameMap[$leaf] + } + return '' +} +function Add-Dependency_Graph([string]$name, [string]$title, [int]$sourceDepth, [int]$targetDepth) { + $files = Get-Source_Files $inputs + $suffixMap = @{} + $nameMap = @{} + foreach ($file in $files) { + $root = Get-Root_For_File $file.FullName + $relative = (Get-Relative_Path $root $file.FullName).ToLowerInvariant() + $leaf = $file.Name.ToLowerInvariant() + $suffixMap[$relative] = $file.FullName + if (!$nameMap.ContainsKey($leaf)) { + $nameMap[$leaf] = $file.FullName + } + } + $edges = @{} + foreach ($file in $files) { + $sourceKey = Get-Module_Key $file.FullName $sourceDepth + if ($sourceKey.Length -eq 0) { + continue + } + Get-Content -LiteralPath $file.FullName | ForEach-Object { + if ($_ -match '^\s*#\s*include\s*[<"]([^">]+)[">]') { + $includeText = $Matches[1] + if (Test-Ignored_Include $includeText) { + return + } + $targetFile = Resolve-Include_Path $includeText $suffixMap $nameMap + if ($targetFile.Length -eq 0) { + return + } + $targetKey = Get-Module_Key $targetFile $targetDepth + if ($targetKey.Length -eq 0 -or $targetKey -eq $sourceKey) { + return + } + $edgeKey = $sourceKey + '|' + $targetKey + if (!$edges.ContainsKey($edgeKey)) { + $edges[$edgeKey] = 0 + } + $edges[$edgeKey]++ + } + } + } + $nodes = [System.Collections.Generic.HashSet[string]]::new() + $lines = [System.Collections.Generic.List[string]]::new() + Add-Header $lines $title + foreach ($edgeKey in $edges.Keys) { + $parts = $edgeKey.Split('|') + $nodes.Add($parts[0]) | Out-Null + $nodes.Add($parts[1]) | Out-Null + } + foreach ($node in $nodes) { + $label = Convert-To_Dot_Text ([System.IO.Path]::GetFileName($node)) + $tooltip = Convert-To_Dot_Text $node + $lines.Add('"' + $node + '" [label="' + $label + '", tooltip="' + $tooltip + '", fillcolor="#dbeafe"];') + } + $edgeIndex = 0 + foreach ($edgeKey in $edges.Keys) { + $parts = $edgeKey.Split('|') + $countNode = 'include_count:' + $edgeIndex + $lines.Add('"' + $countNode + '" [label="include: ' + $edges[$edgeKey] + '", tooltip="' + (Convert-To_Dot_Text $edgeKey) + '", fillcolor="#f8fafc"];') + $lines.Add('"' + $parts[0] + '" -> "' + $countNode + '";') + $lines.Add('"' + $countNode + '" -> "' + $parts[1] + '";') + $edgeIndex++ + } + Add-Legend $lines 'include' + $lines.Add('}') + Invoke-Dot $name $lines +} +function New-Render_Architecture_Graph() { + $lines = [System.Collections.Generic.List[string]]::new() + Add-Header $lines 'radio render_architecture' + $lines.Add('"Plot" [label="Plot", fillcolor="#dbeafe"];') + $lines.Add('"Renderable" [label="Renderable", fillcolor="#dbeafe"];') + $lines.Add('"Render_Data" [label="Render_Data", fillcolor="#dcfce7"];') + $lines.Add('"Render_State" [label="Render_State", fillcolor="#dcfce7"];') + $lines.Add('"Input_Data" [label="Input_Data", fillcolor="#dcfce7"];') + $lines.Add('"Render_Pipeline" [label="Render_Pipeline", fillcolor="#dcfce7"];') + $lines.Add('"State_Buffer" [label="State_Buffer[3]", fillcolor="#fef3c7"];') + $lines.Add('"Input_Buffer" [label="Input_Buffer[3]", fillcolor="#fef3c7"];') + $lines.Add('"Render_Cache" [label="Render_Cache", fillcolor="#fef3c7"];') + $lines.Add('"Color_Buffer" [label="Color_Buffer[3]", fillcolor="#fef3c7"];') + $lines.Add('"CPU_Render_Task" [label="CPU Render Task", fillcolor="#fee2e2"];') + $lines.Add('"Qt_paintEvent" [label="Qt paintEvent", fillcolor="#fee2e2"];') + $lines.Add('"Plot" -> "Renderable" [xlabel="owns/schedules"];') + $lines.Add('"Renderable" -> "Render_Data" [xlabel="owns"];') + $lines.Add('"Render_Data" -> "Render_State" [xlabel="state snapshot"];') + $lines.Add('"Render_Data" -> "Input_Data" [xlabel="input batch"];') + $lines.Add('"Render_Data" -> "Render_Cache" [xlabel="long-lived cache"];') + $lines.Add('"Renderable" -> "Render_Pipeline" [xlabel="submit/finish/publish"];') + $lines.Add('"Render_Pipeline" -> "State_Buffer" [xlabel="edit/ready/render"];') + $lines.Add('"Render_Pipeline" -> "Input_Buffer" [xlabel="write/ready/render"];') + $lines.Add('"Render_Pipeline" -> "CPU_Render_Task" [xlabel="dispatch"];') + $lines.Add('"CPU_Render_Task" -> "Color_Buffer" [xlabel="write render color"];') + $lines.Add('"Color_Buffer" -> "Qt_paintEvent" [xlabel="ready/front consume"];') + Add-Legend $lines 'architecture' + $lines.Add('}') + Invoke-Dot 'radio_render_architecture' $lines +} +New-Directory_Tree_Graph +Add-Dependency_Graph 'radio_module_dependency' 'radio module_dependency' 0 0 +Add-Dependency_Graph 'radio_include_dependency' 'radio include_dependency' 1 1 +New-Render_Architecture_Graph +Write-Graphviz_Index diff --git a/Graphviz/Project_Graphs.sh.in b/Graphviz/Project_Graphs.sh.in new file mode 100644 index 0000000..0863334 --- /dev/null +++ b/Graphviz/Project_Graphs.sh.in @@ -0,0 +1,156 @@ +#!/usr/bin/env bash +set -euo pipefail +inputs=(@PSC_INPUT_DIRS_SH@) +output_dir='@PSC_OUTPUT_DIR@' +format='@PSC_FORMAT@' +dot_exe='@PSC_DOT_EXECUTABLE@' +max_depth=@PSC_MAX_DEPTH@ +collapse_threshold=@PSC_COLLAPSE_THRESHOLD@ +mkdir -p "$output_dir" +normalize_path() { + local path="$1" + if command -v realpath >/dev/null 2>&1; then + realpath -m "$path" | tr '\\' '/' + else + printf '%s\n' "$path" | tr '\\' '/' + fi +} +dot_text() { + printf '%s' "$1" | sed 's/\\/\\//g; s/"/\\"/g' +} +root_name() { + local path + path=$(normalize_path "$1") + case "$path" in + */module/radio) printf 'radio' ;; + */CPP_Core/Core) printf 'CPP_Core' ;; + */YSGraphic_Core) printf 'YSGraphic_Core' ;; + *) basename "$path" ;; + esac +} +write_header() { + local title="$1" + echo "digraph \"$title\" {" + echo 'rankdir=LR;' + echo 'splines=ortho;' + echo 'concentrate=true;' + echo 'forcelabels=true;' + echo "graph [fontname=\"Consolas\", label=\"$title\", labelloc=t, fontsize=18];" + echo 'node [shape=box, style="rounded,filled", fontname="Consolas", fontsize=10];' + echo 'edge [fontname="Consolas", fontsize=9];' +} +write_legend() { + echo 'subgraph cluster_legend {' + echo 'label="legend";' + echo 'style="rounded,dashed";' + echo '"legend_module" [label="module/folder", fillcolor="#dbeafe"];' + echo '"legend_target" [label="cmake target", fillcolor="#dcfce7"];' + echo '"legend_buffer" [label="buffer/cache", fillcolor="#fef3c7"];' + echo '"legend_runtime" [label="runtime", fillcolor="#fee2e2"];' + echo '"legend_edge" [label="edge label = relation/count", fillcolor="#f8fafc"];' + echo '}' +} +render_dot() { + local name="$1" + "$dot_exe" "-T$format" "$output_dir/$name.dot" -o "$output_dir/$name.$format" +} +write_graphviz_index() { + local items=(radio_directory_tree radio_module_dependency radio_cmake_targets radio_include_dependency radio_render_architecture) + { + echo 'Radio Graphviz

Radio Graphviz

' + } > "$output_dir/index.html" +} +write_directory_tree() { + local dot="$output_dir/radio_directory_tree.dot" + { + write_header 'radio directory_tree' + for root in "${inputs[@]}"; do + [ -d "$root" ] || continue + local root_label + root_label=$(root_name "$root") + echo "subgraph \"cluster_$root_label\" {" + echo "label=\"$root_label\";" + echo 'style="rounded";' + find "$root" -maxdepth "$max_depth" -type d | while read -r dir; do + local rel name id files dirs parent parent_id + rel=${dir#"$root"} + rel=${rel#/} + name=$(basename "$dir") + [ -z "$rel" ] && name="$root_label" + id="$root_label${rel:+/$rel}" + files=$(find "$dir" -maxdepth 1 -type f \( -name '*.h' -o -name '*.hpp' -o -name '*.hh' -o -name '*.cpp' -o -name '*.cxx' -o -name '*.cc' \) | wc -l) + dirs=$(find "$dir" -maxdepth 1 -mindepth 1 -type d | wc -l) + echo "\"dir:$id\" [label=\"$(dot_text "$name")\\nfiles: $files\\ndirs: $dirs\", tooltip=\"$(dot_text "$id")\", fillcolor=\"#dbeafe\"];" + if [ -n "$rel" ]; then + parent=$(dirname "$rel") + if [ "$parent" = "." ]; then + parent_id="$root_label" + else + parent_id="$root_label/$parent" + fi + echo "\"dir:$parent_id\" -> \"dir:$id\" [xlabel=\"contains\"];" + fi + done + echo '}' + done + write_legend + echo '}' + } > "$dot" + render_dot 'radio_directory_tree' +} +write_empty_dependency() { + local name="$1" + local title="$2" + { + write_header "$title" + echo '"module_dependency_note" [label="include dependency aggregation is generated by the PowerShell script on Windows", fillcolor="#dbeafe"];' + write_legend + echo '}' + } > "$output_dir/$name.dot" + render_dot "$name" +} +write_render_architecture() { + { + write_header 'radio render_architecture' + echo '"Plot" [label="Plot", fillcolor="#dbeafe"];' + echo '"Renderable" [label="Renderable", fillcolor="#dbeafe"];' + echo '"Render_Data" [label="Render_Data", fillcolor="#dcfce7"];' + echo '"Render_State" [label="Render_State", fillcolor="#dcfce7"];' + echo '"Input_Data" [label="Input_Data", fillcolor="#dcfce7"];' + echo '"Render_Pipeline" [label="Render_Pipeline", fillcolor="#dcfce7"];' + echo '"State_Buffer" [label="State_Buffer[3]", fillcolor="#fef3c7"];' + echo '"Input_Buffer" [label="Input_Buffer[3]", fillcolor="#fef3c7"];' + echo '"Render_Cache" [label="Render_Cache", fillcolor="#fef3c7"];' + echo '"Color_Buffer" [label="Color_Buffer[3]", fillcolor="#fef3c7"];' + echo '"CPU_Render_Task" [label="CPU Render Task", fillcolor="#fee2e2"];' + echo '"Qt_paintEvent" [label="Qt paintEvent", fillcolor="#fee2e2"];' + echo '"Plot" -> "Renderable" [xlabel="owns/schedules"];' + echo '"Renderable" -> "Render_Data" [xlabel="owns"];' + echo '"Render_Data" -> "Render_State" [xlabel="state snapshot"];' + echo '"Render_Data" -> "Input_Data" [xlabel="input batch"];' + echo '"Render_Data" -> "Render_Cache" [xlabel="long-lived cache"];' + echo '"Renderable" -> "Render_Pipeline" [xlabel="submit/finish/publish"];' + echo '"Render_Pipeline" -> "State_Buffer" [xlabel="edit/ready/render"];' + echo '"Render_Pipeline" -> "Input_Buffer" [xlabel="write/ready/render"];' + echo '"Render_Pipeline" -> "CPU_Render_Task" [xlabel="dispatch"];' + echo '"CPU_Render_Task" -> "Color_Buffer" [xlabel="write render color"];' + echo '"Color_Buffer" -> "Qt_paintEvent" [xlabel="ready/front consume"];' + write_legend + echo '}' + } > "$output_dir/radio_render_architecture.dot" + render_dot 'radio_render_architecture' +} +write_directory_tree +write_empty_dependency 'radio_module_dependency' 'radio module_dependency' +write_empty_dependency 'radio_include_dependency' 'radio include_dependency' +write_render_architecture +write_graphviz_index diff --git a/Graphviz/export.cmake b/Graphviz/export.cmake new file mode 100644 index 0000000..44e4407 --- /dev/null +++ b/Graphviz/export.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/main.cmake)