mirror of https://github.com/PCSX2/pcsx2.git
Merge branch 'PCSX2:master' into master
This commit is contained in:
commit
46925c15e9
|
@ -18,6 +18,8 @@ body:
|
||||||
|
|
||||||
Please make an effort to make sure your issue isn't already reported.
|
Please make an effort to make sure your issue isn't already reported.
|
||||||
|
|
||||||
|
Do not create issues involving software piracy of BIOS or ISO files, our rules specifically prohibit this and your issue will be closed.
|
||||||
|
|
||||||
### Please Avoid Issues Pertaining to the Following:
|
### Please Avoid Issues Pertaining to the Following:
|
||||||
- We are **not** accepting bug reports for **PSX mode** at this time.
|
- We are **not** accepting bug reports for **PSX mode** at this time.
|
||||||
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use [Duckstation](https://github.com/stenzek/duckstation/releases/tag/latest).
|
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use [Duckstation](https://github.com/stenzek/duckstation/releases/tag/latest).
|
||||||
|
@ -27,6 +29,9 @@ body:
|
||||||
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues.
|
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues.
|
||||||
- We do **not** accept issues relating to Widescreen/no-interlace patches at this time.
|
- We do **not** accept issues relating to Widescreen/no-interlace patches at this time.
|
||||||
- Any issues pertaining to Widescreen/no-interlace patches please forward them to the [patches repository](https://github.com/PCSX2/pcsx2_patches).
|
- Any issues pertaining to Widescreen/no-interlace patches please forward them to the [patches repository](https://github.com/PCSX2/pcsx2_patches).
|
||||||
|
- We do **not** accept issues pertaining to Linux builds other than the official AppImage and Flatpak.
|
||||||
|
- Please contact your packager for support. We have no control over other builds, nor can we investigate any issues, and historically they have been known to be broken.
|
||||||
|
- This includes pre-configured "distributions" such as EmuDeck, the "AUR", etc.
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: desc
|
id: desc
|
||||||
|
@ -65,11 +70,10 @@ body:
|
||||||
- Windows 11
|
- Windows 11
|
||||||
- Windows 10 (64bit)
|
- Windows 10 (64bit)
|
||||||
- Linux (64bit) - Specify distro below
|
- Linux (64bit) - Specify distro below
|
||||||
|
- macOS 14 (Sonoma)
|
||||||
- macOS 13 (Ventura)
|
- macOS 13 (Ventura)
|
||||||
- macOS 12 (Monterey)
|
- macOS 12 (Monterey)
|
||||||
- macOS 11 (Big Sur)
|
- macOS 11 (Big Sur)
|
||||||
- macOS 10.15 (Catalina)
|
|
||||||
- macOS 10.14 (Mojave)
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
|
|
|
@ -18,6 +18,10 @@ body:
|
||||||
|
|
||||||
Please make an effort to make sure your issue isn't already reported.
|
Please make an effort to make sure your issue isn't already reported.
|
||||||
|
|
||||||
|
Please make sure your game is verified using the built-in game verifier.
|
||||||
|
|
||||||
|
Do not create issues involving software piracy of BIOS or ISO files, our rules specifically prohibit this and your issue will be closed.
|
||||||
|
|
||||||
### Please Avoid Issues Pertaining to the Following:
|
### Please Avoid Issues Pertaining to the Following:
|
||||||
- We are **not** accepting bug reports for **PSX mode** at this time.
|
- We are **not** accepting bug reports for **PSX mode** at this time.
|
||||||
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use [Duckstation](https://github.com/stenzek/duckstation/releases/tag/latest).
|
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use [Duckstation](https://github.com/stenzek/duckstation/releases/tag/latest).
|
||||||
|
@ -27,6 +31,9 @@ body:
|
||||||
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues.
|
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues.
|
||||||
- We do **not** accept issues relating to Widescreen/no-interlace patches at this time.
|
- We do **not** accept issues relating to Widescreen/no-interlace patches at this time.
|
||||||
- Any issues pertaining to Widescreen/no-interlace patches please forward them to the [patches repository](https://github.com/PCSX2/pcsx2_patches).
|
- Any issues pertaining to Widescreen/no-interlace patches please forward them to the [patches repository](https://github.com/PCSX2/pcsx2_patches).
|
||||||
|
- We do **not** accept issues pertaining to Linux builds other than the official AppImage and Flatpak.
|
||||||
|
- Please contact your packager for support. We have no control over other builds, nor can we investigate any issues, and historically they have been known to be broken.
|
||||||
|
- This includes pre-configured "distributions" such as EmuDeck, the "AUR", etc.
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: desc
|
id: desc
|
||||||
|
@ -80,11 +87,10 @@ body:
|
||||||
- Windows 11
|
- Windows 11
|
||||||
- Windows 10 (64bit)
|
- Windows 10 (64bit)
|
||||||
- Linux (64bit) - Specify distro below
|
- Linux (64bit) - Specify distro below
|
||||||
|
- macOS 14 (Sonoma)
|
||||||
- macOS 13 (Ventura)
|
- macOS 13 (Ventura)
|
||||||
- macOS 12 (Monterey)
|
- macOS 12 (Monterey)
|
||||||
- macOS 11 (Big Sur)
|
- macOS 11 (Big Sur)
|
||||||
- macOS 10.15 (Catalina)
|
|
||||||
- macOS 10.14 (Mojave)
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
|
@ -122,9 +128,9 @@ body:
|
||||||
description: |
|
description: |
|
||||||
Any non-default core settings. If you don't want to list them out, please provide screenshots of your configuration window.
|
Any non-default core settings. If you don't want to list them out, please provide screenshots of your configuration window.
|
||||||
|
|
||||||
Please note that the safe preset works for most games. MTVU can have some compatibility issues so please disable it before making a report.
|
Please note that defaults tend to work best.
|
||||||
|
|
||||||
If you need to modify the settings manually because a game requires you to do so to work, please state that explicitly.
|
If you need to modify the settings manually to fix an issue , please state that explicitly.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|
|
@ -2,10 +2,19 @@
|
||||||
name: Feature request
|
name: Feature request
|
||||||
description: Suggest a new feature or improve an existing one
|
description: Suggest a new feature or improve an existing one
|
||||||
title: "[Feature Request]: "
|
title: "[Feature Request]: "
|
||||||
labels: ["Enhancement / Feature Request"]
|
labels: ["Enhancement / Feature Request", "FR: Awaiting Consideration"]
|
||||||
# assignees:
|
# assignees:
|
||||||
# - octocat
|
# - octocat
|
||||||
body:
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Important: Read First
|
||||||
|
|
||||||
|
Please make an effort to make sure your issue isn't already reported.
|
||||||
|
|
||||||
|
Do not create issues involving software piracy of BIOS or ISO files, our rules specifically prohibit this and your issue will be closed.
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: desc
|
id: desc
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -6,3 +6,7 @@ updates:
|
||||||
schedule:
|
schedule:
|
||||||
# Check for updates to GitHub Actions every week
|
# Check for updates to GitHub Actions every week
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
|
groups:
|
||||||
|
ci-deps:
|
||||||
|
patterns:
|
||||||
|
- "*"
|
||||||
|
|
|
@ -2,127 +2,187 @@
|
||||||
|
|
||||||
# General Labels
|
# General Labels
|
||||||
'Build | Project System':
|
'Build | Project System':
|
||||||
- '.github/*'
|
- changed-files:
|
||||||
- '.github/**/*'
|
- any-glob-to-any-file:
|
||||||
- '*.sln'
|
- '.github/*'
|
||||||
- '**/*.sln'
|
- '.github/**/*'
|
||||||
- '*.vcxproj*'
|
- '*.sln'
|
||||||
- '**/*.vcxproj*'
|
- '**/*.sln'
|
||||||
- 'cmake/*'
|
- '*.vcxproj*'
|
||||||
- 'cmake/**/*'
|
- '**/*.vcxproj*'
|
||||||
- 'CMakeLists.txt'
|
- 'cmake/*'
|
||||||
- '**/CMakeLists.txt'
|
- 'cmake/**/*'
|
||||||
- 'build.sh'
|
- 'CMakeLists.txt'
|
||||||
|
- '**/CMakeLists.txt'
|
||||||
|
- 'build.sh'
|
||||||
'Dependencies':
|
'Dependencies':
|
||||||
- '3rdparty/*'
|
- changed-files:
|
||||||
- '3rdparty/**/*'
|
- any-glob-to-any-file:
|
||||||
- '**/3rdpartyDeps.props'
|
- '3rdparty/*'
|
||||||
- '.gitmodules'
|
- '3rdparty/**/*'
|
||||||
|
- '**/3rdpartyDeps.props'
|
||||||
|
- '.gitmodules'
|
||||||
'Documentation':
|
'Documentation':
|
||||||
- '*.md'
|
- changed-files:
|
||||||
- '**/*.md'
|
- any-glob-to-any-file:
|
||||||
- '*.pdf'
|
- '*.md'
|
||||||
- '**/*.pdf'
|
- '**/*.md'
|
||||||
|
- '*.pdf'
|
||||||
|
- '**/*.pdf'
|
||||||
'GUI/Qt':
|
'GUI/Qt':
|
||||||
- 'pcsx2-qt/*'
|
- changed-files:
|
||||||
- 'pcsx2-qt/**/*'
|
- any-glob-to-any-file:
|
||||||
- '3rdparty/Qt/*'
|
- 'pcsx2-qt/*'
|
||||||
- '3rdparty/Qt/**/*'
|
- 'pcsx2-qt/**/*'
|
||||||
|
- '3rdparty/Qt/*'
|
||||||
|
- '3rdparty/Qt/**/*'
|
||||||
'GameDB':
|
'GameDB':
|
||||||
- '**/GameIndex.*'
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/GameIndex.*'
|
||||||
'Installer | Package':
|
'Installer | Package':
|
||||||
- 'build.sh'
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- 'build.sh'
|
||||||
'Translations':
|
'Translations':
|
||||||
- 'pcsx2-qt/Translations/*'
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2-qt/Translations/*'
|
||||||
|
|
||||||
# Tools / Features
|
# Tools / Features
|
||||||
'Debugger':
|
'Debugger':
|
||||||
- 'pcsx2/DebugTools/*'
|
- changed-files:
|
||||||
- 'pcsx2/DebugTools/**/*'
|
- any-glob-to-any-file:
|
||||||
- 'pcsx2-qt/Debugger/*'
|
- 'pcsx2/DebugTools/*'
|
||||||
- 'pcsx2-qt/Debugger/**/*'
|
- 'pcsx2/DebugTools/**/*'
|
||||||
|
- 'pcsx2-qt/Debugger/*'
|
||||||
|
- 'pcsx2-qt/Debugger/**/*'
|
||||||
'IPC':
|
'IPC':
|
||||||
- 'pcsx2/IPC*'
|
- changed-files:
|
||||||
- 'pcsx2/**/IPC*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/IPC*'
|
||||||
|
- 'pcsx2/**/IPC*'
|
||||||
'TAS Functionality':
|
'TAS Functionality':
|
||||||
- 'pcsx2/Recording/*'
|
- changed-files:
|
||||||
- 'pcsx2/Recording/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/Recording/*'
|
||||||
|
- 'pcsx2/Recording/**/*'
|
||||||
'RetroAchievements':
|
'RetroAchievements':
|
||||||
- 'pcsx2/Frontend/Achievements.*'
|
- changed-files:
|
||||||
- 'pcsx2/Achievements.*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/Frontend/Achievements.*'
|
||||||
|
- 'pcsx2/Achievements.*'
|
||||||
|
|
||||||
# Emulation Components
|
# Emulation Components
|
||||||
'Counters':
|
'Counters':
|
||||||
- 'pcsx2/Counters.*'
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/Counters.*'
|
||||||
'Vector Units':
|
'Vector Units':
|
||||||
- 'pcsx2/VU*'
|
- changed-files:
|
||||||
- 'pcsx2/**/VU*'
|
- any-glob-to-any-file:
|
||||||
- 'pcsx2/*VU*'
|
- 'pcsx2/VU*'
|
||||||
- 'pcsx2/**/*VU*'
|
- 'pcsx2/**/VU*'
|
||||||
|
- 'pcsx2/*VU*'
|
||||||
|
- 'pcsx2/**/*VU*'
|
||||||
'VIF':
|
'VIF':
|
||||||
- 'pcsx2/Vif*'
|
- changed-files:
|
||||||
- 'pcsx2/**/Vif*'
|
- any-glob-to-any-file:
|
||||||
- 'pcsx2/VIF*'
|
- 'pcsx2/Vif*'
|
||||||
- 'pcsx2/**/VIF*'
|
- 'pcsx2/**/Vif*'
|
||||||
|
- 'pcsx2/VIF*'
|
||||||
|
- 'pcsx2/**/VIF*'
|
||||||
|
|
||||||
# GS Related Labels
|
# GS Related Labels
|
||||||
'GS':
|
'GS':
|
||||||
- 'pcsx2/GS/*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/**/*'
|
- any-glob-to-any-file:
|
||||||
- 'bin/resources/shaders/*'
|
- 'pcsx2/GS/*'
|
||||||
- 'bin/resources/shaders/**/*'
|
- 'pcsx2/GS/**/*'
|
||||||
|
- 'bin/resources/shaders/*'
|
||||||
|
- 'bin/resources/shaders/**/*'
|
||||||
'GS: Direct3D 11':
|
'GS: Direct3D 11':
|
||||||
- 'pcsx2/GS/Renderers/DX11/*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/Renderers/DX11/**/*'
|
- any-glob-to-any-file:
|
||||||
- 'bin/resources/shaders/dx11/*'
|
- 'pcsx2/GS/Renderers/DX11/*'
|
||||||
- 'bin/resources/shaders/dx11/**/*'
|
- 'pcsx2/GS/Renderers/DX11/**/*'
|
||||||
|
- 'bin/resources/shaders/dx11/*'
|
||||||
|
- 'bin/resources/shaders/dx11/**/*'
|
||||||
'GS: Direct3D 12':
|
'GS: Direct3D 12':
|
||||||
- 'pcsx2/GS/Renderers/DX12/*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/Renderers/DX12/**/*'
|
- any-glob-to-any-file:
|
||||||
- 'bin/resources/shaders/dx11/*'
|
- 'pcsx2/GS/Renderers/DX12/*'
|
||||||
- 'bin/resources/shaders/dx11/**/*'
|
- 'pcsx2/GS/Renderers/DX12/**/*'
|
||||||
|
- 'bin/resources/shaders/dx11/*'
|
||||||
|
- 'bin/resources/shaders/dx11/**/*'
|
||||||
'GS: Hardware':
|
'GS: Hardware':
|
||||||
- 'pcsx2/GS/Renderers/HW/*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/Renderers/HW/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/GS/Renderers/HW/*'
|
||||||
|
- 'pcsx2/GS/Renderers/HW/**/*'
|
||||||
'GS: OpenGL':
|
'GS: OpenGL':
|
||||||
- 'pcsx2/GS/Renderers/OpenGL/*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/Renderers/OpenGL/**/*'
|
- any-glob-to-any-file:
|
||||||
- 'bin/resources/shaders/opengl/*'
|
- 'pcsx2/GS/Renderers/OpenGL/*'
|
||||||
- 'bin/resources/shaders/opengl/**/*'
|
- 'pcsx2/GS/Renderers/OpenGL/**/*'
|
||||||
|
- 'bin/resources/shaders/opengl/*'
|
||||||
|
- 'bin/resources/shaders/opengl/**/*'
|
||||||
'GS: Vulkan':
|
'GS: Vulkan':
|
||||||
- 'pcsx2/GS/Renderers/Vulkan/*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/Renderers/Vulkan/**/*'
|
- any-glob-to-any-file:
|
||||||
- 'bin/resources/shaders/vulkan/*'
|
- 'pcsx2/GS/Renderers/Vulkan/*'
|
||||||
- 'bin/resources/shaders/vulkan/**/*'
|
- 'pcsx2/GS/Renderers/Vulkan/**/*'
|
||||||
|
- 'bin/resources/shaders/vulkan/*'
|
||||||
|
- 'bin/resources/shaders/vulkan/**/*'
|
||||||
'GS: Metal':
|
'GS: Metal':
|
||||||
- 'pcsx2/GS/Renderers/Metal/*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/Renderers/Metal/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/GS/Renderers/Metal/*'
|
||||||
|
- 'pcsx2/GS/Renderers/Metal/**/*'
|
||||||
'GS: Texture Cache':
|
'GS: Texture Cache':
|
||||||
- 'pcsx2/GS/Renderers/*TextureCache*.*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/Renderers/**/*TextureCache*.*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/GS/Renderers/*TextureCache*.*'
|
||||||
|
- 'pcsx2/GS/Renderers/**/*TextureCache*.*'
|
||||||
'GS: Software':
|
'GS: Software':
|
||||||
- 'pcsx2/GS/Renderers/SW/*'
|
- changed-files:
|
||||||
- 'pcsx2/GS/Renderers/SW/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/GS/Renderers/SW/*'
|
||||||
|
- 'pcsx2/GS/Renderers/SW/**/*'
|
||||||
|
|
||||||
# Other Core Components
|
# Other Core Components
|
||||||
'CDVD':
|
'CDVD':
|
||||||
- 'pcsx2/CDVD/*'
|
- changed-files:
|
||||||
- 'pcsx2/CDVD/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/CDVD/*'
|
||||||
|
- 'pcsx2/CDVD/**/*'
|
||||||
'DEV9':
|
'DEV9':
|
||||||
- 'pcsx2/DEV9/*'
|
- changed-files:
|
||||||
- 'pcsx2/DEV9/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/DEV9/*'
|
||||||
|
- 'pcsx2/DEV9/**/*'
|
||||||
'IPU':
|
'IPU':
|
||||||
- 'pcsx2/IPU/*'
|
- changed-files:
|
||||||
- 'pcsx2/IPU/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/IPU/*'
|
||||||
|
- 'pcsx2/IPU/**/*'
|
||||||
'Memory Card':
|
'Memory Card':
|
||||||
- 'pcsx2/SIO/Memcard/*'
|
- changed-files:
|
||||||
- 'pcsx2/SIO/Memcard/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/SIO/Memcard/*'
|
||||||
|
- 'pcsx2/SIO/Memcard/**/*'
|
||||||
'PAD':
|
'PAD':
|
||||||
- 'pcsx2/SIO/Pad/*'
|
- changed-files:
|
||||||
- 'pcsx2/SIO/Pad/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/SIO/Pad/*'
|
||||||
|
- 'pcsx2/SIO/Pad/**/*'
|
||||||
'SPU2':
|
'SPU2':
|
||||||
- 'pcsx2/SPU2/*'
|
- changed-files:
|
||||||
- 'pcsx2/SPU2/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/SPU2/*'
|
||||||
|
- 'pcsx2/SPU2/**/*'
|
||||||
'USB':
|
'USB':
|
||||||
- 'pcsx2/USB/*'
|
- changed-files:
|
||||||
- 'pcsx2/USB/**/*'
|
- any-glob-to-any-file:
|
||||||
|
- 'pcsx2/USB/*'
|
||||||
|
- 'pcsx2/USB/**/*'
|
||||||
|
|
|
@ -23,20 +23,27 @@ jobs:
|
||||||
FLATHUB_RELEASE=$(curl -L -s https://flathub.org/api/v2/appstream/net.pcsx2.PCSX2 | jq -r '.releases | max_by(.version) | .version')
|
FLATHUB_RELEASE=$(curl -L -s https://flathub.org/api/v2/appstream/net.pcsx2.PCSX2 | jq -r '.releases | max_by(.version) | .version')
|
||||||
echo "Latest PCSX2 release is: '${PCSX2_RELEASE}'"
|
echo "Latest PCSX2 release is: '${PCSX2_RELEASE}'"
|
||||||
echo "Latest Flathub release is: '${FLATHUB_RELEASE}'"
|
echo "Latest Flathub release is: '${FLATHUB_RELEASE}'"
|
||||||
|
PCSX2_RELEASE=$(echo $PCSX2_RELEASE | sed 's/[^0-9]*//g')
|
||||||
|
FLATHUB_RELEASE=$(echo $FLATHUB_RELEASE | sed 's/[^0-9]*//g')
|
||||||
echo "PCSX2_RELEASE=${PCSX2_RELEASE}" >> "$GITHUB_OUTPUT"
|
echo "PCSX2_RELEASE=${PCSX2_RELEASE}" >> "$GITHUB_OUTPUT"
|
||||||
echo "FLATHUB_RELEASE=${FLATHUB_RELEASE}" >> "$GITHUB_OUTPUT"
|
echo "FLATHUB_RELEASE=${FLATHUB_RELEASE}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: check
|
needs: check
|
||||||
if: needs.check.outputs.FLATHUB_RELEASE < needs.check.outputs.PCSX2_RELEASE
|
# outputs are automatically compared as strings. This doesn't work in our favour
|
||||||
|
# Use fromJson() to convert them to proper integers...
|
||||||
|
# see: https://github.com/github/docs/pull/25870
|
||||||
|
# and: https://github.com/orgs/community/discussions/57480
|
||||||
|
#if: fromJson(needs.check.outputs.FLATHUB_RELEASE) < fromJson(needs.check.outputs.PCSX2_RELEASE)
|
||||||
name: "Build and publish Flatpak"
|
name: "Build and publish Flatpak"
|
||||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||||
with:
|
with:
|
||||||
jobName: "Qt"
|
jobName: "Qt"
|
||||||
|
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak"
|
||||||
compiler: clang
|
compiler: clang
|
||||||
cmakeflags: ""
|
cmakeflags: ""
|
||||||
publish: true
|
publish: true
|
||||||
branch: stable
|
|
||||||
fetchTags: true
|
fetchTags: true
|
||||||
|
stableBuild: false
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ jobs:
|
||||||
run: ./.github/workflows/scripts/common/update_base_translation.sh
|
run: ./.github/workflows/scripts/common/update_base_translation.sh
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v5
|
uses: peter-evans/create-pull-request@v7
|
||||||
with:
|
with:
|
||||||
title: "Qt: Update Base Translation"
|
title: "Qt: Update Base Translation"
|
||||||
commit-message: "Qt: Update Base Translation"
|
commit-message: "[ci skip] Qt: Update Base Translation."
|
||||||
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
||||||
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
||||||
body: "Daily update of base translation sources."
|
body: "Daily update of base translation sources."
|
||||||
|
|
|
@ -19,11 +19,12 @@ jobs:
|
||||||
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
|
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v5
|
uses: peter-evans/create-pull-request@v7
|
||||||
with:
|
with:
|
||||||
title: "PAD: Update to latest controller database"
|
title: "PAD: Update to latest controller database"
|
||||||
commit-message: "PAD: Update to latest controller database."
|
commit-message: "[ci skip] PAD: Update to latest controller database."
|
||||||
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
||||||
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
||||||
body: "Weekly automatic update of SDL Controller DB"
|
body: "Weekly automatic update of SDL Controller DB."
|
||||||
reviewers: lightningterror
|
branch: update-controller-db
|
||||||
|
delete-branch: true
|
||||||
|
|
|
@ -20,12 +20,24 @@ jobs:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Packages
|
||||||
|
run: |
|
||||||
|
npm install -g ajv-cli prettier
|
||||||
|
sudo apt-get -y install yamllint
|
||||||
|
|
||||||
|
- name: Validate YAML
|
||||||
|
run: |
|
||||||
|
yamllint -sd "{extends: relaxed, rules: {line-length: disable}}" ./bin/resources/GameIndex.yaml
|
||||||
|
|
||||||
- name: Validate Contents
|
- name: Validate Contents
|
||||||
run: |
|
run: |
|
||||||
npm install -g ajv-cli
|
|
||||||
ajv validate -s ./pcsx2/Docs/gamedb-schema.json --spec=draft2020 -d ./bin/resources/GameIndex.yaml
|
ajv validate -s ./pcsx2/Docs/gamedb-schema.json --spec=draft2020 -d ./bin/resources/GameIndex.yaml
|
||||||
|
|
||||||
- name: Check Formatting
|
- name: Check Formatting
|
||||||
run: |
|
run: |
|
||||||
npm install -g prettier
|
if ! prettier --check bin/resources/GameIndex.yaml; then
|
||||||
prettier --check ./bin/resources/GameIndex.yaml
|
prettier --write bin/resources/GameIndex.yaml
|
||||||
|
echo "Prettier failed, diff:"
|
||||||
|
git diff bin/resources/GameIndex.yaml
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
|
@ -6,6 +6,9 @@ on:
|
||||||
jobName:
|
jobName:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
artifactPrefixName:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
os:
|
os:
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
@ -20,10 +23,6 @@ on:
|
||||||
cmakeflags:
|
cmakeflags:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
branch:
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: "stable"
|
|
||||||
publish:
|
publish:
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
@ -36,18 +35,30 @@ on:
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
stableBuild:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_linux:
|
build_linux:
|
||||||
name: ${{ inputs.jobName }}
|
name: ${{ inputs.jobName }}
|
||||||
runs-on: ${{ inputs.os }}
|
runs-on: ${{ inputs.os }}
|
||||||
|
container:
|
||||||
|
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.7
|
||||||
|
options: --privileged
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
set-safe-directory: ${{ env.GITHUB_WORKSPACE }}
|
||||||
|
|
||||||
|
# Work around container ownership issue
|
||||||
|
- name: Set Safe Directory
|
||||||
|
shell: bash
|
||||||
|
run: git config --global --add safe.directory "*"
|
||||||
|
|
||||||
# Hackity hack. When running the workflow on a schedule, we don't have the tag,
|
# Hackity hack. When running the workflow on a schedule, we don't have the tag,
|
||||||
# it doesn't fetch tags, therefore we don't get a version. So grab them manually.
|
# it doesn't fetch tags, therefore we don't get a version. So grab them manually.
|
||||||
|
@ -56,66 +67,97 @@ jobs:
|
||||||
if: ${{ inputs.fetchTags }}
|
if: ${{ inputs.fetchTags }}
|
||||||
run: git fetch --tags --no-recurse-submodules
|
run: git fetch --tags --no-recurse-submodules
|
||||||
|
|
||||||
|
- name: Add stable release identifier file
|
||||||
|
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||||
|
cat ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||||
|
|
||||||
- name: Prepare Artifact Metadata
|
- name: Prepare Artifact Metadata
|
||||||
id: artifact-metadata
|
id: artifact-metadata
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
OS: linux
|
PREFIX: ${{ inputs.artifactPrefixName }}
|
||||||
BUILD_SYSTEM: flatpak
|
|
||||||
ARCH: ${{ inputs.platform }}
|
|
||||||
EVENT_NAME: ${{ github.event_name }}
|
EVENT_NAME: ${{ github.event_name }}
|
||||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||||
PR_NUM: ${{ github.event.pull_request.number }}
|
PR_NUM: ${{ github.event.pull_request.number }}
|
||||||
PR_SHA: ${{ github.event.pull_request.head.sha }}
|
PR_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
run: ./.github/workflows/scripts/common/name-artifacts.sh
|
run: ./.github/workflows/scripts/common/name-artifacts.sh
|
||||||
|
|
||||||
- name: Install Packages
|
|
||||||
env:
|
|
||||||
COMPILER: ${{ inputs.compiler }}
|
|
||||||
run: .github/workflows/scripts/linux/install-packages-flatpak.sh
|
|
||||||
|
|
||||||
- name: Download patches
|
- name: Download patches
|
||||||
run: |
|
run: |
|
||||||
cd bin/resources
|
cd bin/resources
|
||||||
aria2c -Z "${{ inputs.patchesUrl }}/patches.zip"
|
wget "${{ inputs.patchesUrl }}/patches.zip"
|
||||||
|
|
||||||
- name: Generate AppStream XML
|
- name: Validate manifest
|
||||||
run: |
|
run: |
|
||||||
./.github/workflows/scripts/linux/generate-metainfo.sh .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
|
flatpak-builder-lint manifest .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
|
||||||
cat .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
|
|
||||||
flatpak run org.freedesktop.appstream-glib validate .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
|
|
||||||
|
|
||||||
- name: Build Flatpak
|
- name: Build Flatpak (beta)
|
||||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6.2
|
if: ${{ inputs.stableBuild == false || inputs.stableBuild == 'false' }}
|
||||||
|
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||||
with:
|
with:
|
||||||
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||||
|
upload-artifact: false
|
||||||
manifest-path: .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
|
manifest-path: .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
build-bundle: true
|
build-bundle: true
|
||||||
verbose: true
|
verbose: true
|
||||||
mirror-screenshots-url: https://dl.flathub.org/repo/screenshots
|
mirror-screenshots-url: https://dl.flathub.org/media
|
||||||
branch: ${{ inputs.branch }}
|
branch: beta
|
||||||
|
cache: true
|
||||||
|
restore-cache: true
|
||||||
|
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json', '.github/workflows/scripts/common/*.patch') }}
|
||||||
|
|
||||||
|
- name: Build Flatpak (stable)
|
||||||
|
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||||
|
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||||
|
with:
|
||||||
|
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||||
|
upload-artifact: false
|
||||||
|
manifest-path: .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
|
||||||
|
arch: x86_64
|
||||||
|
build-bundle: true
|
||||||
|
verbose: true
|
||||||
|
mirror-screenshots-url: https://dl.flathub.org/media
|
||||||
|
branch: stable
|
||||||
cache: true
|
cache: true
|
||||||
restore-cache: true
|
restore-cache: true
|
||||||
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
|
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
|
||||||
|
|
||||||
- name: Commit screenshots to OSTree
|
#- name: Validate build
|
||||||
run: |
|
# run: |
|
||||||
ostree commit --repo=repo --canonical-permissions --branch=screenshots/x86_64 flatpak_app/screenshots
|
# flatpak-builder-lint repo repo
|
||||||
|
|
||||||
- name: Push to Flathub beta
|
- name: Push to Flathub (beta)
|
||||||
if: inputs.publish == true && inputs.branch == 'beta'
|
if: ${{ inputs.publish == true && (inputs.stableBuild == false || inputs.stableBuild == 'false') }}
|
||||||
uses: flatpak/flatpak-github-actions/flat-manager@v6.2
|
uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||||
with:
|
with:
|
||||||
flat-manager-url: https://hub.flathub.org/
|
flat-manager-url: https://hub.flathub.org/
|
||||||
repository: beta
|
repository: beta
|
||||||
token: ${{ secrets.FLATHUB_BETA_TOKEN }}
|
token: ${{ secrets.FLATHUB_BETA_TOKEN }}
|
||||||
|
build-log-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
|
||||||
- name: Push to Flathub stable
|
- name: Push to Flathub (stable)
|
||||||
if: inputs.publish == true && inputs.branch == 'stable'
|
if: ${{ inputs.publish == true && (inputs.stableBuild == true || inputs.stableBuild == 'true') }}
|
||||||
uses: flatpak/flatpak-github-actions/flat-manager@v6.2
|
uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||||
with:
|
with:
|
||||||
flat-manager-url: https://hub.flathub.org/
|
flat-manager-url: https://hub.flathub.org/
|
||||||
repository: stable
|
repository: stable
|
||||||
token: ${{ secrets.FLATHUB_TOKEN }}
|
token: ${{ secrets.FLATHUB_TOKEN }}
|
||||||
|
build-log-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
|
||||||
|
# NOTE - this is done after on purpose so the flatpak file is wherever it needs to be for the previous pushes
|
||||||
|
- name: Prepare artifacts folder
|
||||||
|
# NOTE - 'flatpak-builder' dumps the artifact out into the current directory
|
||||||
|
run: |
|
||||||
|
mkdir -p "$GITHUB_WORKSPACE"/ci-artifacts/
|
||||||
|
mv "./${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak" "$GITHUB_WORKSPACE"/ci-artifacts/
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||||
|
path: ci-artifacts
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ jobs:
|
||||||
uses: ./.github/workflows/linux_build_qt.yml
|
uses: ./.github/workflows/linux_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "AppImage Build"
|
jobName: "AppImage Build"
|
||||||
|
artifactPrefixName: "PCSX2-linux-Qt-x64-appimage-sse4"
|
||||||
compiler: clang
|
compiler: clang
|
||||||
cmakeflags: ""
|
cmakeflags: ""
|
||||||
buildAppImage: true
|
buildAppImage: true
|
||||||
|
@ -25,6 +26,7 @@ jobs:
|
||||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||||
with:
|
with:
|
||||||
jobName: "Flatpak Build"
|
jobName: "Flatpak Build"
|
||||||
|
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak-sse4"
|
||||||
compiler: clang
|
compiler: clang
|
||||||
cmakeflags: ""
|
cmakeflags: ""
|
||||||
publish: false
|
publish: false
|
||||||
|
|
|
@ -6,6 +6,9 @@ on:
|
||||||
jobName:
|
jobName:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
artifactPrefixName:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
os:
|
os:
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
@ -36,13 +39,17 @@ on:
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
stableBuild:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_linux:
|
build_linux:
|
||||||
name: ${{ inputs.jobName }}
|
name: ${{ inputs.jobName }}
|
||||||
runs-on: ${{ inputs.os }}
|
runs-on: ${{ inputs.os }}
|
||||||
# Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them.
|
# Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them.
|
||||||
timeout-minutes: 60
|
timeout-minutes: 90
|
||||||
env:
|
env:
|
||||||
CCACHE_BASEDIR: ${{ github.workspace }}
|
CCACHE_BASEDIR: ${{ github.workspace }}
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||||
|
@ -54,19 +61,25 @@ jobs:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
fetch-depth: 0
|
||||||
|
|
||||||
# actions/checkout elides tags, fetch them primarily for releases
|
# actions/checkout elides tags, fetch them primarily for releases
|
||||||
- name: Fetch Tags
|
- name: Fetch Tags
|
||||||
if: ${{ inputs.fetchTags }}
|
if: ${{ inputs.fetchTags }}
|
||||||
run: git fetch --tags --no-recurse-submodules
|
run: git fetch --tags --no-recurse-submodules
|
||||||
|
|
||||||
|
- name: Add stable release identifier file
|
||||||
|
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||||
|
cat ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||||
|
|
||||||
- name: Prepare Artifact Metadata
|
- name: Prepare Artifact Metadata
|
||||||
id: artifact-metadata
|
id: artifact-metadata
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
OS: linux
|
PREFIX: ${{ inputs.artifactPrefixName }}
|
||||||
ARCH: ${{ inputs.platform }}
|
|
||||||
EVENT_NAME: ${{ github.event_name }}
|
EVENT_NAME: ${{ github.event_name }}
|
||||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||||
PR_NUM: ${{ github.event.pull_request.number }}
|
PR_NUM: ${{ github.event.pull_request.number }}
|
||||||
|
@ -79,27 +92,36 @@ jobs:
|
||||||
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: ccache cache files
|
- name: ccache cache files
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .ccache
|
path: .ccache
|
||||||
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||||
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache
|
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache
|
||||||
|
|
||||||
- name: Install Packages
|
- name: Install Packages
|
||||||
env:
|
run: |
|
||||||
COMPILER: ${{ inputs.compiler }}
|
tools/retry.sh wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||||
run: .github/workflows/scripts/linux/install-packages-qt.sh
|
sudo tools/retry.sh apt-add-repository -n 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main'
|
||||||
|
sudo tools/retry.sh apt-get update
|
||||||
|
sudo tools/retry.sh apt-get -y install \
|
||||||
|
build-essential ccache clang-17 cmake curl extra-cmake-modules git libasound2-dev libaio-dev libavcodec-dev libavformat-dev libavutil-dev \
|
||||||
|
libcurl4-openssl-dev libdbus-1-dev libdecor-0-dev libegl-dev libevdev-dev libfontconfig-dev libfreetype-dev libfuse2 libgtk-3-dev libgudev-1.0-dev \
|
||||||
|
libharfbuzz-dev libinput-dev libopengl-dev libpcap-dev libpipewire-0.3-dev libpulse-dev libssl-dev libswresample-dev libswscale-dev libudev-dev \
|
||||||
|
libwayland-dev libx11-dev libx11-xcb-dev libxcb1-dev libxcb-composite0-dev libxcb-cursor-dev libxcb-damage0-dev libxcb-glx0-dev libxcb-icccm4-dev \
|
||||||
|
libxcb-image0-dev libxcb-keysyms1-dev libxcb-present-dev libxcb-randr0-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-shape0-dev \
|
||||||
|
libxcb-shm0-dev libxcb-sync-dev libxcb-util-dev libxcb-xfixes0-dev libxcb-xinput-dev libxcb-xkb-dev libxext-dev libxkbcommon-x11-dev libxrandr-dev \
|
||||||
|
lld-17 llvm-17 ninja-build patchelf pkg-config zlib1g-dev
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
id: cache-deps
|
id: cache-deps
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/deps
|
path: ~/deps
|
||||||
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh') }}
|
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh', '.github/workflows/scripts/common/*.patch') }}
|
||||||
|
|
||||||
- name: Build Dependencies
|
- name: Build Dependencies
|
||||||
if: steps.cache-deps.outputs.cache-hit != 'true'
|
if: steps.cache-deps.outputs.cache-hit != 'true'
|
||||||
run: .github/workflows/scripts/linux/build-dependencies-qt.sh
|
run: .github/workflows/scripts/linux/build-dependencies-qt.sh "$HOME/deps"
|
||||||
|
|
||||||
- name: Download patches
|
- name: Download patches
|
||||||
run: |
|
run: |
|
||||||
|
@ -108,16 +130,31 @@ jobs:
|
||||||
|
|
||||||
- name: Generate CMake
|
- name: Generate CMake
|
||||||
env:
|
env:
|
||||||
COMPILER: ${{ inputs.compiler }}
|
|
||||||
ADDITIONAL_CMAKE_ARGS: ${{ inputs.cmakeflags }}
|
ADDITIONAL_CMAKE_ARGS: ${{ inputs.cmakeflags }}
|
||||||
CLANG_PATH: /usr/bin/clang-16
|
|
||||||
CLANGXX_PATH: /usr/bin/clang++-16
|
|
||||||
run: |
|
run: |
|
||||||
DEPS_PREFIX="$HOME/deps" .github/workflows/scripts/linux/generate-cmake-qt.sh
|
cmake -B build -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||||
|
-DCMAKE_PREFIX_PATH="$HOME/deps" \
|
||||||
|
-DCMAKE_C_COMPILER=clang-17 \
|
||||||
|
-DCMAKE_CXX_COMPILER=clang++-17 \
|
||||||
|
-DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" \
|
||||||
|
-DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DENABLE_SETCAP=OFF \
|
||||||
|
-DDISABLE_ADVANCE_SIMD=TRUE \
|
||||||
|
$ADDITIONAL_CMAKE_ARGS
|
||||||
|
|
||||||
- name: Build PCSX2
|
- name: Build PCSX2
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: ../.github/workflows/scripts/linux/compile.sh
|
run: |
|
||||||
|
# Prepare the Cache
|
||||||
|
ccache -p
|
||||||
|
ccache -z
|
||||||
|
# Build
|
||||||
|
ninja
|
||||||
|
# Save the Cache
|
||||||
|
ccache -s
|
||||||
|
|
||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
working-directory: ./build
|
working-directory: ./build
|
||||||
|
@ -134,7 +171,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
if: inputs.buildAppImage == true
|
if: inputs.buildAppImage == true
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||||
path: ci-artifacts
|
path: ci-artifacts
|
||||||
|
|
|
@ -6,10 +6,13 @@ on:
|
||||||
jobName:
|
jobName:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
artifactPrefixName:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
os:
|
os:
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
default: macos-13
|
default: macos-14
|
||||||
patchesUrl:
|
patchesUrl:
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
@ -18,6 +21,10 @@ on:
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
stableBuild:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_macos:
|
build_macos:
|
||||||
|
@ -36,22 +43,27 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
# actions/checkout elides tags, fetch them primarily for releases
|
# actions/checkout elides tags, fetch them primarily for releases
|
||||||
- name: Fetch Tags
|
- name: Fetch Tags
|
||||||
if: ${{ inputs.fetchTags }}
|
if: ${{ inputs.fetchTags }}
|
||||||
run: git fetch --tags --no-recurse-submodules
|
run: git fetch --tags --no-recurse-submodules
|
||||||
|
|
||||||
- name: Use Xcode 14.3.1
|
- name: Add stable release identifier file
|
||||||
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
|
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||||
|
cat ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||||
|
|
||||||
|
- name: Use Xcode 15.2
|
||||||
|
run: sudo xcode-select -s /Applications/Xcode_15.2.app
|
||||||
|
|
||||||
- name: Prepare Artifact Metadata
|
- name: Prepare Artifact Metadata
|
||||||
id: artifact-metadata
|
id: artifact-metadata
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
OS: macos
|
PREFIX: ${{ inputs.artifactPrefixName }}
|
||||||
EVENT_NAME: ${{ github.event_name }}
|
EVENT_NAME: ${{ github.event_name }}
|
||||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||||
PR_NUM: ${{ github.event.pull_request.number }}
|
PR_NUM: ${{ github.event.pull_request.number }}
|
||||||
|
@ -60,28 +72,25 @@ jobs:
|
||||||
|
|
||||||
- name: Install Packages
|
- name: Install Packages
|
||||||
env:
|
env:
|
||||||
PLATFORM: "x64"
|
|
||||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||||
HOMEBREW_NO_ANALYTICS: 1
|
HOMEBREW_NO_ANALYTICS: 1
|
||||||
run: |
|
run: |
|
||||||
brew unlink libjpeg || true # Conflicts with our self-built dependencies
|
if ! brew install ccache nasm; then
|
||||||
brew unlink libpng || true
|
|
||||||
# Unlike other packages, brew's MoltenVK build uses MoltenVK's minimum macOS version of 10.13 so we can use it
|
|
||||||
if ! brew install molten-vk ccache nasm; then
|
|
||||||
brew update
|
brew update
|
||||||
brew install molten-vk ccache nasm
|
brew install ccache nasm
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
id: cache-deps
|
id: cache-deps
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/deps
|
path: ~/deps
|
||||||
key: ${{ inputs.os }} deps ${{ hashFiles('.github/workflows/scripts/macos/build-dependencies.sh') }}
|
key: ${{ inputs.os }} deps ${{ hashFiles('.github/workflows/scripts/macos/build-dependencies.sh', '.github/workflows/scripts/common/*.patch') }}
|
||||||
|
|
||||||
- name: Build Dependencies
|
- name: Build Dependencies
|
||||||
if: steps.cache-deps.outputs.cache-hit != 'true'
|
if: steps.cache-deps.outputs.cache-hit != 'true'
|
||||||
run: .github/workflows/scripts/macos/build-dependencies.sh
|
run: |
|
||||||
|
.github/workflows/scripts/macos/build-dependencies.sh "$HOME/deps"
|
||||||
|
|
||||||
- name: Download patches
|
- name: Download patches
|
||||||
run: |
|
run: |
|
||||||
|
@ -94,7 +103,7 @@ jobs:
|
||||||
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Cache ccache cache
|
- name: Cache ccache cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .ccache
|
path: .ccache
|
||||||
key: ${{ inputs.os }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
key: ${{ inputs.os }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||||
|
@ -104,12 +113,9 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
cmake -DCMAKE_PREFIX_PATH="$HOME/deps" \
|
cmake -DCMAKE_PREFIX_PATH="$HOME/deps" \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
-DUSE_OPENGL=OFF \
|
-DCMAKE_OSX_ARCHITECTURES="x86_64" \
|
||||||
-DUSE_VULKAN=OFF \
|
|
||||||
-DDISABLE_ADVANCE_SIMD=ON \
|
-DDISABLE_ADVANCE_SIMD=ON \
|
||||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||||
-DUSE_SYSTEM_LIBS=OFF \
|
|
||||||
-DUSE_SYSTEM_SDL2=ON \
|
|
||||||
-DUSE_LINKED_FFMPEG=ON \
|
-DUSE_LINKED_FFMPEG=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
@ -138,7 +144,6 @@ jobs:
|
||||||
|
|
||||||
- name: Prepare Build Artifacts
|
- name: Prepare Build Artifacts
|
||||||
run: |
|
run: |
|
||||||
cp /usr/local/lib/libMoltenVK.dylib build/pcsx2*/PCSX2.app/Contents/Frameworks/
|
|
||||||
TAG="$(git tag --points-at HEAD)"
|
TAG="$(git tag --points-at HEAD)"
|
||||||
if [ -z "$TAG" ]; then
|
if [ -z "$TAG" ]; then
|
||||||
APPNAME="${{ steps.artifact-metadata.outputs.artifact-name }}"
|
APPNAME="${{ steps.artifact-metadata.outputs.artifact-name }}"
|
||||||
|
@ -151,7 +156,7 @@ jobs:
|
||||||
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
|
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||||
path: "*.tar.xz"
|
path: "*.tar.xz"
|
||||||
|
|
|
@ -15,4 +15,5 @@ jobs:
|
||||||
uses: ./.github/workflows/macos_build.yml
|
uses: ./.github/workflows/macos_build.yml
|
||||||
with:
|
with:
|
||||||
jobName: "MacOS Build"
|
jobName: "MacOS Build"
|
||||||
|
artifactPrefixName: "PCSX2-macos-Qt"
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
|
@ -10,16 +10,19 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
# TODO - future work
|
workflow_dispatch:
|
||||||
# workflow_dispatch:
|
inputs:
|
||||||
# inputs:
|
is_prelease:
|
||||||
# isStable:
|
description: 'Should be a pre-release?'
|
||||||
# description: 'Should it be a stable release?'
|
required: true
|
||||||
# required: true
|
default: 'true'
|
||||||
# default: 'false'
|
type: choice
|
||||||
# versionTag:
|
options:
|
||||||
# description: 'The version to tag with'
|
- 'true'
|
||||||
# required: true
|
- 'false'
|
||||||
|
tag_value:
|
||||||
|
description: 'Create a new release from latest master with the given tag, if this is left blank it will bump the patch version. You dont need to include the "v" prefix'
|
||||||
|
required: false
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
@ -37,11 +40,13 @@ jobs:
|
||||||
# Docs - https://github.com/mathieudutour/github-tag-action
|
# Docs - https://github.com/mathieudutour/github-tag-action
|
||||||
- name: Bump Version and Push Tag
|
- name: Bump Version and Push Tag
|
||||||
id: tag_version
|
id: tag_version
|
||||||
uses: mathieudutour/github-tag-action@v6.1
|
uses: mathieudutour/github-tag-action@v6.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ github.token }}
|
github_token: ${{ github.token }}
|
||||||
tag_prefix: v
|
tag_prefix: v
|
||||||
default_bump: patch
|
default_bump: patch
|
||||||
|
# if set, it will overwrite the bump settings
|
||||||
|
custom_tag: ${{ github.event.inputs.tag_value == '' && null || github.event.inputs.tag_value }}
|
||||||
|
|
||||||
# TODO - we could do this and remove the node.js script, but auto-generated notes only work
|
# TODO - we could do this and remove the node.js script, but auto-generated notes only work
|
||||||
# with PRs -- not commits (determine how much we care).
|
# with PRs -- not commits (determine how much we care).
|
||||||
|
@ -62,9 +67,18 @@ jobs:
|
||||||
node index.js
|
node index.js
|
||||||
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
|
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
|
||||||
|
|
||||||
- name: Create a GitHub Release
|
- name: Create a GitHub Release (Manual)
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
if: steps.tag_version.outputs.new_tag
|
if: steps.tag_version.outputs.new_tag && github.event_name == 'workflow_dispatch'
|
||||||
|
with:
|
||||||
|
body_path: ./release-notes.md
|
||||||
|
draft: true
|
||||||
|
prerelease: ${{ github.event_name != 'workflow_dispatch' || inputs.is_prelease == 'true' }}
|
||||||
|
tag_name: ${{ steps.tag_version.outputs.new_tag }}
|
||||||
|
|
||||||
|
- name: Create a GitHub Release (Push)
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
if: steps.tag_version.outputs.new_tag && github.event_name != 'workflow_dispatch'
|
||||||
with:
|
with:
|
||||||
body_path: ./release-notes.md
|
body_path: ./release-notes.md
|
||||||
draft: true
|
draft: true
|
||||||
|
@ -81,10 +95,12 @@ jobs:
|
||||||
uses: ./.github/workflows/linux_build_qt.yml
|
uses: ./.github/workflows/linux_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "AppImage Build"
|
jobName: "AppImage Build"
|
||||||
|
artifactPrefixName: "PCSX2-linux-Qt-x64-appimage"
|
||||||
compiler: clang
|
compiler: clang
|
||||||
cmakeflags: ""
|
cmakeflags: ""
|
||||||
buildAppImage: true
|
buildAppImage: true
|
||||||
fetchTags: true
|
fetchTags: true
|
||||||
|
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
build_linux_flatpak:
|
build_linux_flatpak:
|
||||||
|
@ -95,11 +111,12 @@ jobs:
|
||||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||||
with:
|
with:
|
||||||
jobName: "Flatpak Build"
|
jobName: "Flatpak Build"
|
||||||
|
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak"
|
||||||
compiler: clang
|
compiler: clang
|
||||||
cmakeflags: ""
|
cmakeflags: ""
|
||||||
branch: "stable"
|
|
||||||
publish: false
|
publish: false
|
||||||
fetchTags: true
|
fetchTags: true
|
||||||
|
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
# Windows
|
# Windows
|
||||||
|
@ -111,10 +128,12 @@ jobs:
|
||||||
uses: ./.github/workflows/windows_build_qt.yml
|
uses: ./.github/workflows/windows_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "Windows Build"
|
jobName: "Windows Build"
|
||||||
|
artifactPrefixName: "PCSX2-windows-Qt-x64"
|
||||||
configuration: CMake
|
configuration: CMake
|
||||||
buildSystem: cmake
|
buildSystem: cmake
|
||||||
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
|
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
|
||||||
fetchTags: true
|
fetchTags: true
|
||||||
|
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
# MacOS
|
# MacOS
|
||||||
|
@ -126,7 +145,9 @@ jobs:
|
||||||
uses: ./.github/workflows/macos_build.yml
|
uses: ./.github/workflows/macos_build.yml
|
||||||
with:
|
with:
|
||||||
jobName: "MacOS Build"
|
jobName: "MacOS Build"
|
||||||
|
artifactPrefixName: "PCSX2-macos-Qt"
|
||||||
fetchTags: true
|
fetchTags: true
|
||||||
|
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
# Upload the Artifacts
|
# Upload the Artifacts
|
||||||
|
@ -146,7 +167,7 @@ jobs:
|
||||||
- name: Prepare Artifact Folder
|
- name: Prepare Artifact Folder
|
||||||
run: mkdir ./ci-artifacts/
|
run: mkdir ./ci-artifacts/
|
||||||
|
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v4
|
||||||
name: Download all Artifacts
|
name: Download all Artifacts
|
||||||
with:
|
with:
|
||||||
path: ./ci-artifacts/
|
path: ./ci-artifacts/
|
||||||
|
@ -159,9 +180,6 @@ jobs:
|
||||||
working-directory: ./ci-artifacts/
|
working-directory: ./ci-artifacts/
|
||||||
run: for d in *windows*/; do 7z a "${d}asset.7z" ./$d/*; done
|
run: for d in *windows*/; do 7z a "${d}asset.7z" ./$d/*; done
|
||||||
|
|
||||||
# Artifact Naming:
|
|
||||||
# MacOS: PCSX2-<tag>-macOS-[additional hyphen seperated tags]
|
|
||||||
# Windows|Linux: PCSX2-<tag>-<windows|linux>-<32bit|64bit>--[additional hyphen seperated tags]
|
|
||||||
- name: Name and Upload the Release Assets
|
- name: Name and Upload the Release Assets
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
@ -184,7 +202,7 @@ jobs:
|
||||||
echo "TAG_VAL=${TAG_VAL}"
|
echo "TAG_VAL=${TAG_VAL}"
|
||||||
gh release edit ${TAG_VAL} --draft=false --repo PCSX2/pcsx2
|
gh release edit ${TAG_VAL} --draft=false --repo PCSX2/pcsx2
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,26 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Artifact Naming Scheme:
|
# Artifact Naming Scheme:
|
||||||
# PCSX2-<OS>-Qt-[ARCH]-[SIMD]-[pr\[PR_NUM\]]-[title|sha\[SHA|PR_TITLE\]
|
# PCSX2-<OS>-Qt-[BUILD_SYSTEM]-[ARCH]-[SIMD]-[pr\[PR_NUM\]]-[title|sha\[SHA|PR_TITLE\]
|
||||||
# -- limited to 200 chars
|
# -- limited to 200 chars
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# - artifact-name
|
# - artifact-name
|
||||||
|
|
||||||
|
# Example - PCSX2-linux-Qt-x64-flatpak-sse4-sha[e880a2749]
|
||||||
|
|
||||||
# Inputs as env-vars
|
# Inputs as env-vars
|
||||||
# OS
|
# PREFIX
|
||||||
# BUILD_SYSTEM
|
|
||||||
# ARCH
|
|
||||||
# SIMD
|
|
||||||
# EVENT_NAME
|
# EVENT_NAME
|
||||||
# PR_TITLE
|
# PR_TITLE
|
||||||
# PR_NUM
|
# PR_NUM
|
||||||
# PR_SHA
|
# PR_SHA
|
||||||
|
|
||||||
NAME=""
|
if [[ -z "${PREFIX}" ]]; then
|
||||||
|
echo "PREFIX is not set, can't name artifact without it!"
|
||||||
if [ "${OS}" == "macos" ]; then
|
exit 1
|
||||||
# MacOS has combined binaries for x64 and ARM64.
|
|
||||||
NAME="PCSX2-${OS}-Qt"
|
|
||||||
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") ]]; then
|
|
||||||
NAME="PCSX2-${OS}-Qt-${ARCH}-${SIMD}"
|
|
||||||
else
|
|
||||||
NAME="PCSX2-${OS}-Qt-${ARCH}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add cmake if used to differentate it from msbuild builds
|
NAME="${PREFIX}"
|
||||||
# Else the two artifacts will have the same name and the files will be merged
|
|
||||||
if [[ ! -z "${BUILD_SYSTEM}" ]]; then
|
|
||||||
if [[ "${BUILD_SYSTEM}" == "cmake" ]] || [[ "${BUILD_SYSTEM}" == "flatpak" ]]; then
|
|
||||||
NAME="${NAME}-${BUILD_SYSTEM}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add PR / Commit Metadata
|
# Add PR / Commit Metadata
|
||||||
if [ "$EVENT_NAME" == "pull_request" ]; then
|
if [ "$EVENT_NAME" == "pull_request" ]; then
|
||||||
|
|
|
@ -0,0 +1,270 @@
|
||||||
|
diff --git a/CHANGES b/CHANGES
|
||||||
|
index 5d3dd16..587b612 100644
|
||||||
|
--- a/CHANGES
|
||||||
|
+++ b/CHANGES
|
||||||
|
@@ -4,7 +4,7 @@ v2024.1
|
||||||
|
- Update dependencies
|
||||||
|
- Propagate test/install options to Glslang
|
||||||
|
|
||||||
|
-v2024.0
|
||||||
|
+v2024.0 2024-03-09
|
||||||
|
- Update dependencies
|
||||||
|
- Utilities:
|
||||||
|
- Use Python3 explicitly in utility scripts
|
||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index ffcb54b..7c1a6d8 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -117,6 +117,9 @@ if(MSVC)
|
||||||
|
endif()
|
||||||
|
endif(MSVC)
|
||||||
|
|
||||||
|
+if(NOT WIN32)
|
||||||
|
+ add_definitions("-fvisibility=hidden")
|
||||||
|
+endif()
|
||||||
|
|
||||||
|
# Configure subdirectories.
|
||||||
|
# We depend on these for later projects, so they should come first.
|
||||||
|
@@ -124,7 +127,6 @@ add_subdirectory(third_party)
|
||||||
|
|
||||||
|
add_subdirectory(libshaderc_util)
|
||||||
|
add_subdirectory(libshaderc)
|
||||||
|
-add_subdirectory(glslc)
|
||||||
|
if(${SHADERC_ENABLE_EXAMPLES})
|
||||||
|
add_subdirectory(examples)
|
||||||
|
endif()
|
||||||
|
@@ -158,5 +160,3 @@ function(define_pkg_config_file NAME LIBS)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
define_pkg_config_file(shaderc -lshaderc_shared)
|
||||||
|
-define_pkg_config_file(shaderc_static "-lshaderc ${EXTRA_STATIC_PKGCONFIG_LIBS} -lshaderc_util")
|
||||||
|
-define_pkg_config_file(shaderc_combined -lshaderc_combined)
|
||||||
|
diff --git a/libshaderc/CMakeLists.txt b/libshaderc/CMakeLists.txt
|
||||||
|
index df9a88d..b15e5d7 100644
|
||||||
|
--- a/libshaderc/CMakeLists.txt
|
||||||
|
+++ b/libshaderc/CMakeLists.txt
|
||||||
|
@@ -24,13 +24,6 @@ set(SHADERC_SOURCES
|
||||||
|
src/shaderc_private.h
|
||||||
|
)
|
||||||
|
|
||||||
|
-add_library(shaderc STATIC ${SHADERC_SOURCES})
|
||||||
|
-shaderc_default_compile_options(shaderc)
|
||||||
|
-target_include_directories(shaderc
|
||||||
|
- PUBLIC include
|
||||||
|
- PRIVATE ${glslang_SOURCE_DIR}
|
||||||
|
- ${SPIRV-Headers_SOURCE_DIR}/include)
|
||||||
|
-
|
||||||
|
add_library(shaderc_shared SHARED ${SHADERC_SOURCES})
|
||||||
|
shaderc_default_compile_options(shaderc_shared)
|
||||||
|
target_include_directories(shaderc_shared
|
||||||
|
@@ -54,7 +47,7 @@ if(SHADERC_ENABLE_INSTALL)
|
||||||
|
DESTINATION
|
||||||
|
${CMAKE_INSTALL_INCLUDEDIR}/shaderc)
|
||||||
|
|
||||||
|
- install(TARGETS shaderc shaderc_shared
|
||||||
|
+ install(TARGETS shaderc_shared
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
@@ -69,20 +62,8 @@ set(SHADERC_LIBS
|
||||||
|
SPIRV-Tools
|
||||||
|
)
|
||||||
|
|
||||||
|
-target_link_libraries(shaderc PRIVATE ${SHADERC_LIBS})
|
||||||
|
target_link_libraries(shaderc_shared PRIVATE ${SHADERC_LIBS})
|
||||||
|
|
||||||
|
-shaderc_add_tests(
|
||||||
|
- TEST_PREFIX shaderc
|
||||||
|
- LINK_LIBS shaderc
|
||||||
|
- INCLUDE_DIRS include ${shaderc_SOURCE_DIR}/libshaderc_util/include ${glslang_SOURCE_DIR}
|
||||||
|
- ${spirv-tools_SOURCE_DIR}/include
|
||||||
|
- ${SPIRV-Headers_SOURCE_DIR}/include
|
||||||
|
- TEST_NAMES
|
||||||
|
- shaderc
|
||||||
|
- shaderc_cpp
|
||||||
|
- shaderc_private)
|
||||||
|
-
|
||||||
|
shaderc_add_tests(
|
||||||
|
TEST_PREFIX shaderc_shared
|
||||||
|
LINK_LIBS shaderc_shared SPIRV-Tools
|
||||||
|
@@ -94,22 +75,6 @@ shaderc_add_tests(
|
||||||
|
shaderc_cpp
|
||||||
|
shaderc_private)
|
||||||
|
|
||||||
|
-shaderc_combine_static_lib(shaderc_combined shaderc)
|
||||||
|
-
|
||||||
|
-if(SHADERC_ENABLE_INSTALL)
|
||||||
|
- install(TARGETS shaderc_combined DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||||
|
-endif(SHADERC_ENABLE_INSTALL)
|
||||||
|
-
|
||||||
|
-shaderc_add_tests(
|
||||||
|
- TEST_PREFIX shaderc_combined
|
||||||
|
- LINK_LIBS shaderc_combined ${CMAKE_THREAD_LIBS_INIT}
|
||||||
|
- INCLUDE_DIRS include ${shaderc_SOURCE_DIR}/libshaderc_util/include ${glslang_SOURCE_DIR}
|
||||||
|
- ${spirv-tools_SOURCE_DIR}/include
|
||||||
|
- ${SPIRV-Headers_SOURCE_DIR}/include
|
||||||
|
- TEST_NAMES
|
||||||
|
- shaderc
|
||||||
|
- shaderc_cpp)
|
||||||
|
-
|
||||||
|
if(${SHADERC_ENABLE_TESTS})
|
||||||
|
add_executable(shaderc_c_smoke_test ./src/shaderc_c_smoke_test.c)
|
||||||
|
shaderc_default_c_compile_options(shaderc_c_smoke_test)
|
||||||
|
diff --git a/libshaderc/include/shaderc/shaderc.h b/libshaderc/include/shaderc/shaderc.h
|
||||||
|
index 3a3e97d..65d5b77 100644
|
||||||
|
--- a/libshaderc/include/shaderc/shaderc.h
|
||||||
|
+++ b/libshaderc/include/shaderc/shaderc.h
|
||||||
|
@@ -15,6 +15,8 @@
|
||||||
|
#ifndef SHADERC_SHADERC_H_
|
||||||
|
#define SHADERC_SHADERC_H_
|
||||||
|
|
||||||
|
+#define SHADERC_PCSX2_CUSTOM 1
|
||||||
|
+
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
@@ -317,7 +317,7 @@ SHADERC_EXPORT void shaderc_compile_options_set_source_language(
|
||||||
|
|
||||||
|
// Sets the compiler mode to generate debug information in the output.
|
||||||
|
SHADERC_EXPORT void shaderc_compile_options_set_generate_debug_info(
|
||||||
|
- shaderc_compile_options_t options);
|
||||||
|
+ shaderc_compile_options_t options, bool enabled, bool enable_non_semantic);
|
||||||
|
|
||||||
|
// Sets the compiler optimization level to the given level. Only the last one
|
||||||
|
// takes effect if multiple calls of this function exist.
|
||||||
|
diff --git a/libshaderc/include/shaderc/shaderc.hpp b/libshaderc/include/shaderc/shaderc.hpp
|
||||||
|
index 3817af8..5592b49 100644
|
||||||
|
--- a/libshaderc/include/shaderc/shaderc.hpp
|
||||||
|
+++ b/libshaderc/include/shaderc/shaderc.hpp
|
||||||
|
@@ -168,8 +168,9 @@ class CompileOptions {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the compiler mode to generate debug information in the output.
|
||||||
|
- void SetGenerateDebugInfo() {
|
||||||
|
- shaderc_compile_options_set_generate_debug_info(options_);
|
||||||
|
+ void SetGenerateDebugInfo(bool enabled, bool non_semantic_debug_info) {
|
||||||
|
+ shaderc_compile_options_set_generate_debug_info(options_, enabled,
|
||||||
|
+ non_sematic_debug_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the compiler optimization level to the given level. Only the last one
|
||||||
|
diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc
|
||||||
|
index 63f1bbc..c1a9b12 100644
|
||||||
|
--- a/libshaderc/src/shaderc.cc
|
||||||
|
+++ b/libshaderc/src/shaderc.cc
|
||||||
|
@@ -418,8 +418,12 @@ void shaderc_compile_options_set_source_language(
|
||||||
|
}
|
||||||
|
|
||||||
|
void shaderc_compile_options_set_generate_debug_info(
|
||||||
|
- shaderc_compile_options_t options) {
|
||||||
|
- options->compiler.SetGenerateDebugInfo();
|
||||||
|
+ shaderc_compile_options_t options, bool enabled, bool enable_non_semantic) {
|
||||||
|
+ if (enabled) {
|
||||||
|
+ options->compiler.SetGenerateDebugInfo();
|
||||||
|
+ if (enable_non_semantic)
|
||||||
|
+ options->compiler.SetEmitNonSemanticDebugInfo();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
void shaderc_compile_options_set_optimization_level(
|
||||||
|
diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h
|
||||||
|
index d9d02b9..b076ec8 100644
|
||||||
|
--- a/libshaderc_util/include/libshaderc_util/compiler.h
|
||||||
|
+++ b/libshaderc_util/include/libshaderc_util/compiler.h
|
||||||
|
@@ -195,6 +195,7 @@ class Compiler {
|
||||||
|
warnings_as_errors_(false),
|
||||||
|
suppress_warnings_(false),
|
||||||
|
generate_debug_info_(false),
|
||||||
|
+ emit_non_semantic_debug_info_(false),
|
||||||
|
enabled_opt_passes_(),
|
||||||
|
target_env_(TargetEnv::Vulkan),
|
||||||
|
target_env_version_(TargetEnvVersion::Default),
|
||||||
|
@@ -220,6 +221,10 @@ class Compiler {
|
||||||
|
// such as identifier names and line numbers.
|
||||||
|
void SetGenerateDebugInfo();
|
||||||
|
|
||||||
|
+ // Requests that the compiler emit non-semantic debug information.
|
||||||
|
+ // Requires VK_KHR_shader_non_semantic_info.
|
||||||
|
+ void SetEmitNonSemanticDebugInfo();
|
||||||
|
+
|
||||||
|
// Sets the optimization level to the given level. Only the last one takes
|
||||||
|
// effect if multiple calls of this method exist.
|
||||||
|
void SetOptimizationLevel(OptimizationLevel level);
|
||||||
|
@@ -486,6 +491,10 @@ class Compiler {
|
||||||
|
// output.
|
||||||
|
bool generate_debug_info_;
|
||||||
|
|
||||||
|
+ // When true and generate_debug_info_ is also set, generate non-semantic debug
|
||||||
|
+ // information.
|
||||||
|
+ bool emit_non_semantic_debug_info_;
|
||||||
|
+
|
||||||
|
// Optimization passes to be applied.
|
||||||
|
std::vector<PassId> enabled_opt_passes_;
|
||||||
|
|
||||||
|
diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc
|
||||||
|
index e5f5d10..1f9e6a5 100644
|
||||||
|
--- a/libshaderc_util/src/compiler.cc
|
||||||
|
+++ b/libshaderc_util/src/compiler.cc
|
||||||
|
@@ -341,6 +341,11 @@ std::tuple<bool, std::vector<uint32_t>, size_t> Compiler::Compile(
|
||||||
|
options.generateDebugInfo = generate_debug_info_;
|
||||||
|
options.disableOptimizer = true;
|
||||||
|
options.optimizeSize = false;
|
||||||
|
+ options.emitNonSemanticShaderDebugInfo =
|
||||||
|
+ generate_debug_info_ && emit_non_semantic_debug_info_;
|
||||||
|
+ options.emitNonSemanticShaderDebugSource =
|
||||||
|
+ generate_debug_info_ && emit_non_semantic_debug_info_;
|
||||||
|
+
|
||||||
|
// Note the call to GlslangToSpv also populates compilation_output_data.
|
||||||
|
glslang::GlslangToSpv(*program.getIntermediate(used_shader_stage), spirv,
|
||||||
|
&options);
|
||||||
|
@@ -438,6 +443,10 @@ void Compiler::SetGenerateDebugInfo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+void Compiler::SetEmitNonSemanticDebugInfo() {
|
||||||
|
+ emit_non_semantic_debug_info_ = true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void Compiler::SetOptimizationLevel(Compiler::OptimizationLevel level) {
|
||||||
|
// Clear previous settings first.
|
||||||
|
enabled_opt_passes_.clear();
|
||||||
|
diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt
|
||||||
|
index d44f62a..83966b6 100644
|
||||||
|
--- a/third_party/CMakeLists.txt
|
||||||
|
+++ b/third_party/CMakeLists.txt
|
||||||
|
@@ -20,9 +20,9 @@ set(SHADERC_TINT_DIR "${SHADERC_THIRD_PARTY_ROOT_DIR}/tint" CACHE STRING
|
||||||
|
set(SHADERC_ABSL_DIR "${SHADERC_THIRD_PARTY_ROOT_DIR}/abseil_cpp" CACHE STRING
|
||||||
|
"Location of re2 source")
|
||||||
|
|
||||||
|
-set( SKIP_GLSLANG_INSTALL ${SHADERC_SKIP_INSTALL} )
|
||||||
|
-set( SKIP_SPIRV_TOOLS_INSTALL ${SHADERC_SKIP_INSTALL} )
|
||||||
|
-set( SKIP_GOOGLETEST_INSTALL ${SHADERC_SKIP_INSTALL} )
|
||||||
|
+set( SKIP_GLSLANG_INSTALL ON )
|
||||||
|
+set( SKIP_SPIRV_TOOLS_INSTALL ON )
|
||||||
|
+set( SKIP_GOOGLETEST_INSTALL ON )
|
||||||
|
|
||||||
|
# Configure third party projects.
|
||||||
|
if(${SHADERC_ENABLE_TESTS})
|
||||||
|
@@ -64,7 +64,10 @@ if (NOT TARGET SPIRV-Tools)
|
||||||
|
add_subdirectory(${SHADERC_RE2_DIR} re2)
|
||||||
|
add_subdirectory(${SHADERC_EFFCEE_DIR} effcee)
|
||||||
|
endif()
|
||||||
|
- add_subdirectory(${SHADERC_SPIRV_TOOLS_DIR} spirv-tools)
|
||||||
|
+ set(SPIRV_SKIP_EXECUTABLES ON CACHE BOOL "Skip building SPIRV-Tools executables")
|
||||||
|
+ set(SPIRV_TOOLS_BUILD_STATIC OFF CACHE BOOL "Skip building two SPIRV-Tools libs")
|
||||||
|
+ set(SPIRV_TOOLS_LIBRARY_TYPE STATIC CACHE STRING "Build static SPIRV-Tools libs")
|
||||||
|
+ add_subdirectory(${SHADERC_SPIRV_TOOLS_DIR} spirv-tools EXCLUDE_FROM_ALL)
|
||||||
|
if (NOT "${SPIRV_SKIP_TESTS}")
|
||||||
|
if (MSVC)
|
||||||
|
if (${MSVC_VERSION} LESS 1920)
|
||||||
|
@@ -87,8 +90,8 @@ if (NOT TARGET glslang)
|
||||||
|
# Glslang tests are off by default. Turn them on if testing Shaderc.
|
||||||
|
set(GLSLANG_TESTS ON)
|
||||||
|
endif()
|
||||||
|
- set(GLSLANG_ENABLE_INSTALL $<NOT:${SKIP_GLSLANG_INSTALL}>)
|
||||||
|
- add_subdirectory(${SHADERC_GLSLANG_DIR} glslang)
|
||||||
|
+ set(GLSLANG_ENABLE_INSTALL OFF)
|
||||||
|
+ add_subdirectory(${SHADERC_GLSLANG_DIR} glslang EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
if (NOT TARGET glslang)
|
||||||
|
message(FATAL_ERROR "glslang was not found - required for compilation")
|
|
@ -1,12 +1,14 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
||||||
source "$SCRIPTDIR/../linux/functions.sh"
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# While we use custom Qt builds for our releases, the Qt6 package will be good enough
|
# While we use custom Qt builds for our releases, the Qt6 package will be good enough
|
||||||
# for just updating translations. Saves building it for this action alone.
|
# for just updating translations. Saves building it for this action alone.
|
||||||
retry_command sudo apt-get -y install qt6-l10n-tools
|
"$SCRIPTDIR/../../../../tools/retry.sh" sudo apt-get -y install qt6-l10n-tools python3
|
||||||
|
|
||||||
PATH=/usr/lib/qt6/bin:$PATH "$SCRIPTDIR/../../../../pcsx2-qt/Translations/update_en_translation.sh"
|
"$SCRIPTDIR/../../../../tools/generate_fullscreen_ui_translation_strings.py"
|
||||||
|
"$SCRIPTDIR/../../../../pcsx2-qt/Translations/update_glyph_ranges.py"
|
||||||
|
"$SCRIPTDIR/../../../../tools/generate_update_fa_glyph_ranges.py"
|
||||||
|
PATH=/usr/lib/qt6/bin:$PATH "$SCRIPTDIR/../../../../pcsx2-qt/Translations/update_base_translation.sh"
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
# For more information, please refer to <http://unlicense.org/>
|
# For more information, please refer to <http://unlicense.org/>
|
||||||
|
|
||||||
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
||||||
source "$SCRIPTDIR/functions.sh"
|
|
||||||
|
|
||||||
if [ "$#" -ne 4 ]; then
|
if [ "$#" -ne 4 ]; then
|
||||||
echo "Syntax: $0 <path to pcsx2 directory> <path to build directory> <deps prefix> <output name>"
|
echo "Syntax: $0 <path to pcsx2 directory> <path to build directory> <deps prefix> <output name>"
|
||||||
|
@ -42,6 +41,10 @@ BINARY=pcsx2-qt
|
||||||
APPDIRNAME=PCSX2.AppDir
|
APPDIRNAME=PCSX2.AppDir
|
||||||
STRIP=strip
|
STRIP=strip
|
||||||
|
|
||||||
|
declare -a MANUAL_LIBS=(
|
||||||
|
"libshaderc_shared.so.1"
|
||||||
|
)
|
||||||
|
|
||||||
declare -a MANUAL_QT_LIBS=(
|
declare -a MANUAL_QT_LIBS=(
|
||||||
"libQt6WaylandEglClientHwIntegration.so.6"
|
"libQt6WaylandEglClientHwIntegration.so.6"
|
||||||
)
|
)
|
||||||
|
@ -52,32 +55,58 @@ declare -a MANUAL_QT_PLUGINS=(
|
||||||
"wayland-shell-integration"
|
"wayland-shell-integration"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
declare -a REMOVE_LIBS=(
|
||||||
|
'libwayland-client.so*'
|
||||||
|
'libwayland-cursor.so*'
|
||||||
|
'libwayland-egl.so*'
|
||||||
|
)
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
LINUXDEPLOY=./linuxdeploy-x86_64.AppImage
|
LINUXDEPLOY=./linuxdeploy-x86_64
|
||||||
LINUXDEPLOY_PLUGIN_QT=./linuxdeploy-plugin-qt-x86_64.AppImage
|
LINUXDEPLOY_PLUGIN_QT=./linuxdeploy-plugin-qt-x86_64
|
||||||
APPIMAGETOOL=./appimagetool-x86_64.AppImage
|
APPIMAGETOOL=./appimagetool-x86_64
|
||||||
PATCHELF=patchelf
|
PATCHELF=patchelf
|
||||||
|
|
||||||
if [ ! -f "$LINUXDEPLOY" ]; then
|
if [ ! -f "$LINUXDEPLOY" ]; then
|
||||||
retry_command wget -O "$LINUXDEPLOY" https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
"$PCSX2DIR/tools/retry.sh" wget -O "$LINUXDEPLOY" https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
||||||
chmod +x "$LINUXDEPLOY"
|
chmod +x "$LINUXDEPLOY"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "$LINUXDEPLOY_PLUGIN_QT" ]; then
|
if [ ! -f "$LINUXDEPLOY_PLUGIN_QT" ]; then
|
||||||
retry_command wget -O "$LINUXDEPLOY_PLUGIN_QT" https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
|
"$PCSX2DIR/tools/retry.sh" wget -O "$LINUXDEPLOY_PLUGIN_QT" https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
|
||||||
chmod +x "$LINUXDEPLOY_PLUGIN_QT"
|
chmod +x "$LINUXDEPLOY_PLUGIN_QT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Using go-appimage
|
||||||
|
# Backported from https://github.com/stenzek/duckstation/pull/3251
|
||||||
if [ ! -f "$APPIMAGETOOL" ]; then
|
if [ ! -f "$APPIMAGETOOL" ]; then
|
||||||
retry_command wget -O "$APPIMAGETOOL" https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
APPIMAGETOOLURL=$(wget -q https://api.github.com/repos/probonopd/go-appimage/releases -O - | sed 's/[()",{} ]/\n/g' | grep -o 'https.*continuous.*tool.*86_64.*mage$' | head -1)
|
||||||
|
"$PCSX2DIR/tools/retry.sh" wget -O "$APPIMAGETOOL" "$APPIMAGETOOLURL"
|
||||||
chmod +x "$APPIMAGETOOL"
|
chmod +x "$APPIMAGETOOL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OUTDIR=$(realpath "./$APPDIRNAME")
|
OUTDIR=$(realpath "./$APPDIRNAME")
|
||||||
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
|
||||||
rm -fr "$OUTDIR"
|
rm -fr "$OUTDIR"
|
||||||
|
|
||||||
|
echo "Locating extra libraries..."
|
||||||
|
EXTRA_LIBS_ARGS=""
|
||||||
|
for lib in "${MANUAL_LIBS[@]}"; do
|
||||||
|
srcpath=$(find "$DEPSDIR" -name "$lib")
|
||||||
|
if [ ! -f "$srcpath" ]; then
|
||||||
|
echo "Missinge extra library $lib. Exiting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Found $lib at $srcpath."
|
||||||
|
|
||||||
|
if [ "$EXTRA_LIBS_ARGS" == "" ]; then
|
||||||
|
EXTRA_LIBS_ARGS="--library=$srcpath"
|
||||||
|
else
|
||||||
|
EXTRA_LIBS_ARGS="$EXTRA_LIBS_ARGS,$srcpath"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Why the nastyness? linuxdeploy strips our main binary, and there's no option to turn it off.
|
# Why the nastyness? linuxdeploy strips our main binary, and there's no option to turn it off.
|
||||||
# It also doesn't strip the Qt libs. We can't strip them after running linuxdeploy, because
|
# It also doesn't strip the Qt libs. We can't strip them after running linuxdeploy, because
|
||||||
# patchelf corrupts the libraries (but they still work), but patchelf+strip makes them crash
|
# patchelf corrupts the libraries (but they still work), but patchelf+strip makes them crash
|
||||||
|
@ -99,11 +128,12 @@ cp "$PCSX2DIR/.github/workflows/scripts/linux/pcsx2-qt.desktop" "net.pcsx2.PCSX2
|
||||||
cp "$PCSX2DIR/bin/resources/icons/AppIconLarge.png" "PCSX2.png"
|
cp "$PCSX2DIR/bin/resources/icons/AppIconLarge.png" "PCSX2.png"
|
||||||
|
|
||||||
echo "Running linuxdeploy to create AppDir..."
|
echo "Running linuxdeploy to create AppDir..."
|
||||||
EXTRA_QT_PLUGINS="core;gui;network;svg;waylandclient;widgets;xcbqpa" \
|
EXTRA_QT_PLUGINS="core;gui;svg;waylandclient;widgets;xcbqpa" \
|
||||||
EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" \
|
EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" \
|
||||||
|
DEPLOY_PLATFORM_THEMES="1" \
|
||||||
QMAKE="$DEPSDIR/bin/qmake" \
|
QMAKE="$DEPSDIR/bin/qmake" \
|
||||||
NO_STRIP="1" \
|
NO_STRIP="1" \
|
||||||
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/pcsx2-qt" \
|
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/pcsx2-qt" $EXTRA_LIBS_ARGS \
|
||||||
--desktop-file="net.pcsx2.PCSX2.desktop" --icon-file="PCSX2.png"
|
--desktop-file="net.pcsx2.PCSX2.desktop" --icon-file="PCSX2.png"
|
||||||
|
|
||||||
echo "Copying resources into AppDir..."
|
echo "Copying resources into AppDir..."
|
||||||
|
@ -137,13 +167,22 @@ for GROUP in "${MANUAL_QT_PLUGINS[@]}"; do
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Why do we have to manually remove these libs? Because the linuxdeploy Qt plugin
|
||||||
|
# copies them, not the "main" linuxdeploy binary, and plugins don't inherit the
|
||||||
|
# include list...
|
||||||
|
for lib in "${REMOVE_LIBS[@]}"; do
|
||||||
|
for libpath in $(find "$OUTDIR/usr/lib" -name "$lib"); do
|
||||||
|
echo " Removing problematic library ${libpath}."
|
||||||
|
rm -f "$libpath"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
# Restore unstripped deps (for cache).
|
# Restore unstripped deps (for cache).
|
||||||
rm -fr "$DEPSDIR"
|
rm -fr "$DEPSDIR"
|
||||||
mv "$DEPSDIR.bak" "$DEPSDIR"
|
mv "$DEPSDIR.bak" "$DEPSDIR"
|
||||||
|
|
||||||
# Fix up translations.
|
# Fix up translations.
|
||||||
rm -fr "$OUTDIR/usr/bin/translations"
|
rm -fr "$OUTDIR/usr/bin/translations" "$OUTDIR/usr/translations"
|
||||||
mv "$OUTDIR/usr/translations" "$OUTDIR/usr/bin"
|
|
||||||
cp -a "$BUILDDIR/bin/translations" "$OUTDIR/usr/bin"
|
cp -a "$BUILDDIR/bin/translations" "$OUTDIR/usr/bin"
|
||||||
|
|
||||||
# Generate AppStream meta-info.
|
# Generate AppStream meta-info.
|
||||||
|
@ -151,7 +190,28 @@ echo "Generating AppStream metainfo..."
|
||||||
mkdir -p "$OUTDIR/usr/share/metainfo"
|
mkdir -p "$OUTDIR/usr/share/metainfo"
|
||||||
"$SCRIPTDIR/generate-metainfo.sh" "$OUTDIR/usr/share/metainfo/net.pcsx2.PCSX2.appdata.xml"
|
"$SCRIPTDIR/generate-metainfo.sh" "$OUTDIR/usr/share/metainfo/net.pcsx2.PCSX2.appdata.xml"
|
||||||
|
|
||||||
echo "Generating AppImage..."
|
# Copy in AppRun hooks.
|
||||||
rm -f "$NAME.AppImage"
|
# Unfortunately linuxdeploy is a bit lame and doesn't let us provide our own AppRun hooks, instead
|
||||||
$APPIMAGETOOL -v "$OUTDIR" "$NAME.AppImage"
|
# they have to come from plugins.. and screw writing one of those just to disable Wayland.
|
||||||
|
echo "Copying AppRun hooks..."
|
||||||
|
mkdir -p "$OUTDIR/apprun-hooks"
|
||||||
|
for hookpath in "$SCRIPTDIR/apprun-hooks"/*; do
|
||||||
|
hookname=$(basename "$hookpath")
|
||||||
|
cp -v "$hookpath" "$OUTDIR/apprun-hooks/$hookname"
|
||||||
|
sed -i -e 's/exec /source "$this_dir"\/apprun-hooks\/"'"$hookname"'"\nexec /' "$OUTDIR/AppRun"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Generating AppImage..."
|
||||||
|
GIT_VERSION=$(git tag --points-at HEAD)
|
||||||
|
|
||||||
|
if [[ "${GIT_VERSION}" == "" ]]; then
|
||||||
|
# In the odd event that we run this script before the release gets tagged.
|
||||||
|
GIT_VERSION=$(git describe --tags)
|
||||||
|
if [[ "${GIT_VERSION}" == "" ]]; then
|
||||||
|
GIT_VERSION=$(git rev-parse HEAD)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$NAME.AppImage"
|
||||||
|
ARCH=x86_64 VERSION="${GIT_VERSION}" "$APPIMAGETOOL" -s "$OUTDIR" && mv ./*.AppImage "$NAME.AppImage"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
if [[ -z "$I_WANT_A_BROKEN_WAYLAND_UI" ]]; then
|
||||||
|
echo "Forcing X11 instead of Wayland, due to various protocol limitations"
|
||||||
|
echo "and Qt issues. If you want to use Wayland, launch PCSX2 with"
|
||||||
|
echo "I_WANT_A_BROKEN_WAYLAND_UI=YES set."
|
||||||
|
export QT_QPA_PLATFORM=xcb
|
||||||
|
else
|
||||||
|
echo "Wayland is not being disabled. Do not complain when things break."
|
||||||
|
fi
|
||||||
|
|
|
@ -2,52 +2,141 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
INSTALLDIR="$HOME/deps"
|
if [ "$#" -ne 1 ]; then
|
||||||
|
echo "Syntax: $0 <output directory>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPTDIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
|
||||||
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
||||||
SDL=SDL2-2.28.2
|
INSTALLDIR="$1"
|
||||||
QT=6.5.2
|
if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||||
|
INSTALLDIR="$PWD/$INSTALLDIR"
|
||||||
|
fi
|
||||||
|
|
||||||
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
|
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
|
||||||
|
LIBJPEG=9f
|
||||||
|
LIBPNG=1.6.44
|
||||||
|
LIBWEBP=1.4.0
|
||||||
|
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||||
|
SDL=SDL2-2.30.10
|
||||||
|
QT=6.8.1
|
||||||
|
ZSTD=1.5.6
|
||||||
|
|
||||||
|
SHADERC=2024.1
|
||||||
|
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||||
|
SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
|
||||||
|
SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||||
|
|
||||||
mkdir -p deps-build
|
mkdir -p deps-build
|
||||||
cd deps-build
|
cd deps-build
|
||||||
|
|
||||||
cat > SHASUMS <<EOF
|
cat > SHASUMS <<EOF
|
||||||
64b1102fa22093515b02ef33dd8739dee1ba57e9dbba6a092942b8bbed1a1c5e $SDL.tar.gz
|
|
||||||
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
|
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
|
||||||
3db4c729b4d80a9d8fda8dd77128406353baff4755ca619177eda4cddae71269 qtbase-everywhere-src-$QT.tar.xz
|
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
|
||||||
aae0c08924c6a5e47f9d57e031673d611ffff7aab2bee2e1cc460471ecac6743 qtimageformats-everywhere-src-$QT.tar.xz
|
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
|
||||||
48b4cc1093af2e0ab3bea30f60651bddd877a2335d16e7207879a2e9e81963a3 qtsvg-everywhere-src-$QT.tar.xz
|
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
|
||||||
551ffb22751d8fd4d88e9ebd55b9131f4ca55341ee497fdbbba4da8d10d94341 qttools-everywhere-src-$QT.tar.xz
|
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||||
337c45637e757e754c2f0ea65c20de3e6e53a841dda1253db15baa622515beeb qttranslations-everywhere-src-$QT.tar.xz
|
f59adf36a0fcf4c94198e7d3d776c1b3824211ab7aeebeb31fe19836661196aa $SDL.tar.gz
|
||||||
3020be86fb7fd0abb8509906ca6583cadcaee168159abceaeb5b3e9d42563c9a qtwayland-everywhere-src-$QT.tar.xz
|
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||||
|
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
|
||||||
|
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
|
||||||
|
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
|
||||||
|
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
|
||||||
|
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
|
||||||
|
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
|
||||||
|
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
|
||||||
|
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||||
|
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||||
|
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
curl -L \
|
curl -L \
|
||||||
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
|
||||||
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
|
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
|
||||||
|
-O "https://ijg.org/files/jpegsrc.v$LIBJPEG.tar.gz" \
|
||||||
|
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||||
|
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||||
|
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||||
|
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
||||||
|
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz"
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz" \
|
||||||
|
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
|
||||||
|
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||||
|
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||||
|
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz"
|
||||||
|
|
||||||
shasum -a 256 --check SHASUMS
|
shasum -a 256 --check SHASUMS
|
||||||
|
|
||||||
echo "Building SDL..."
|
echo "Building libbacktrace..."
|
||||||
tar xf "$SDL.tar.gz"
|
rm -fr "libbacktrace-$LIBBACKTRACE"
|
||||||
cd "$SDL"
|
unzip "$LIBBACKTRACE.zip"
|
||||||
./configure --prefix "$INSTALLDIR" --disable-dbus --without-x --disable-video-opengl --disable-video-opengles --disable-video-vulkan --disable-wayland-shared --disable-ime --disable-oss --disable-alsa --disable-jack --disable-esd --disable-pipewire --disable-pulseaudio --disable-arts --disable-nas --disable-sndio --disable-fusionsound --disable-diskaudio
|
cd "libbacktrace-$LIBBACKTRACE"
|
||||||
make "-j$NPROCS"
|
./configure --prefix="$INSTALLDIR"
|
||||||
|
make
|
||||||
make install
|
make install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
echo "Building libbacktrace..."
|
echo "Building libpng..."
|
||||||
unzip "$LIBBACKTRACE.zip"
|
rm -fr "libpng-$LIBPNG"
|
||||||
cd "libbacktrace-$LIBBACKTRACE"
|
tar xf "libpng-$LIBPNG.tar.xz"
|
||||||
./configure --prefix="$HOME/deps"
|
cd "libpng-$LIBPNG"
|
||||||
make
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -DPNG_STATIC=OFF -DPNG_SHARED=ON -DPNG_TOOLS=OFF -B build -G Ninja
|
||||||
|
cmake --build build --parallel
|
||||||
|
ninja -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Building libjpeg..."
|
||||||
|
rm -fr "jpeg-$LIBJPEG"
|
||||||
|
tar xf "jpegsrc.v$LIBJPEG.tar.gz"
|
||||||
|
cd "jpeg-$LIBJPEG"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
../configure --prefix="$INSTALLDIR" --disable-static --enable-shared
|
||||||
|
make "-j$NPROCS"
|
||||||
make install
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo "Building LZ4..."
|
||||||
|
rm -fr "lz4-$LZ4"
|
||||||
|
tar xf "$LZ4.tar.gz"
|
||||||
|
cd "lz4-$LZ4"
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -B build-dir -G Ninja build/cmake
|
||||||
|
cmake --build build-dir --parallel
|
||||||
|
ninja -C build-dir install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Building Zstandard..."
|
||||||
|
rm -fr "zstd-$ZSTD"
|
||||||
|
tar xf "zstd-$ZSTD.tar.gz"
|
||||||
|
cd "zstd-$ZSTD"
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
|
||||||
|
cmake --build build --parallel
|
||||||
|
ninja -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Building WebP..."
|
||||||
|
rm -fr "libwebp-$LIBWEBP"
|
||||||
|
tar xf "libwebp-$LIBWEBP.tar.gz"
|
||||||
|
cd "libwebp-$LIBWEBP"
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -B build -G Ninja \
|
||||||
|
-DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF \
|
||||||
|
-DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON
|
||||||
|
cmake --build build --parallel
|
||||||
|
ninja -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Building SDL..."
|
||||||
|
rm -fr "$SDL"
|
||||||
|
tar xf "$SDL.tar.gz"
|
||||||
|
cd "$SDL"
|
||||||
|
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja
|
||||||
|
cmake --build build --parallel
|
||||||
|
ninja -C build install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
# Couple notes:
|
# Couple notes:
|
||||||
|
@ -56,65 +145,54 @@ cd ..
|
||||||
# ICU avoids pulling in a bunch of large libraries, and hopefully we can get away without it.
|
# ICU avoids pulling in a bunch of large libraries, and hopefully we can get away without it.
|
||||||
# OpenGL is needed to render window decorations in Wayland, apparently.
|
# OpenGL is needed to render window decorations in Wayland, apparently.
|
||||||
echo "Building Qt Base..."
|
echo "Building Qt Base..."
|
||||||
|
rm -fr "qtbase-everywhere-src-$QT"
|
||||||
tar xf "qtbase-everywhere-src-$QT.tar.xz"
|
tar xf "qtbase-everywhere-src-$QT.tar.xz"
|
||||||
cd "qtbase-everywhere-src-$QT"
|
cd "qtbase-everywhere-src-$QT"
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
../configure -prefix "$INSTALLDIR" -release -no-dbus -gui -widgets -fontconfig -qt-doubleconversion -ssl -openssl-runtime -opengl desktop -qpa xcb,wayland -xkbcommon -- -DFEATURE_dbus=OFF -DFEATURE_icu=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF
|
../configure -prefix "$INSTALLDIR" -release -dbus-linked -gui -widgets -fontconfig -qt-doubleconversion -ssl -openssl-runtime -opengl desktop -qpa xcb,wayland -xkbcommon -xcb -gtk -- -DFEATURE_dbus=ON -DFEATURE_icu=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
|
||||||
cmake --build . --parallel
|
cmake --build . --parallel
|
||||||
cmake --install .
|
ninja install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
echo "Building Qt SVG..."
|
echo "Building Qt SVG..."
|
||||||
|
rm -fr "qtsvg-everywhere-src-$QT"
|
||||||
tar xf "qtsvg-everywhere-src-$QT.tar.xz"
|
tar xf "qtsvg-everywhere-src-$QT.tar.xz"
|
||||||
cd "qtsvg-everywhere-src-$QT"
|
cd "qtsvg-everywhere-src-$QT"
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -G Ninja -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release ..
|
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR"
|
||||||
cmake --build . --parallel
|
cmake --build . --parallel
|
||||||
cmake --install .
|
ninja install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
echo "Building Qt Image Formats..."
|
echo "Building Qt Image Formats..."
|
||||||
|
rm -fr "qtimageformats-everywhere-src-$QT"
|
||||||
tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
|
tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
|
||||||
cd "qtimageformats-everywhere-src-$QT"
|
cd "qtimageformats-everywhere-src-$QT"
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -G Ninja -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release ..
|
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_system_webp=ON
|
||||||
cmake --build . --parallel
|
cmake --build . --parallel
|
||||||
cmake --install .
|
ninja install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
echo "Building Qt Wayland..."
|
echo "Building Qt Wayland..."
|
||||||
|
rm -fr "qtwayland-everywhere-src-$QT"
|
||||||
tar xf "qtwayland-everywhere-src-$QT.tar.xz"
|
tar xf "qtwayland-everywhere-src-$QT.tar.xz"
|
||||||
cd "qtwayland-everywhere-src-$QT"
|
cd "qtwayland-everywhere-src-$QT"
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -G Ninja -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release ..
|
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR"
|
||||||
cmake --build . --parallel
|
cmake --build . --parallel
|
||||||
cmake --install .
|
ninja install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
echo "Installing Qt Tools..."
|
echo "Installing Qt Tools..."
|
||||||
|
rm -fr "qttools-everywhere-src-$QT"
|
||||||
tar xf "qttools-everywhere-src-$QT.tar.xz"
|
tar xf "qttools-everywhere-src-$QT.tar.xz"
|
||||||
cd "qttools-everywhere-src-$QT"
|
cd "qttools-everywhere-src-$QT"
|
||||||
# From Mac build-dependencies.sh:
|
# Force disable clang scanning, it gets very confused.
|
||||||
# Linguist relies on a library in the Designer target, which takes 5-7 minutes to build on the CI
|
|
||||||
# Avoid it by not building Linguist, since we only need the tools that come with it
|
|
||||||
patch -u src/linguist/CMakeLists.txt <<EOF
|
|
||||||
--- src/linguist/CMakeLists.txt
|
|
||||||
+++ src/linguist/CMakeLists.txt
|
|
||||||
@@ -14,7 +14,7 @@
|
|
||||||
add_subdirectory(lrelease-pro)
|
|
||||||
add_subdirectory(lupdate)
|
|
||||||
add_subdirectory(lupdate-pro)
|
|
||||||
-if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png)
|
|
||||||
+if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND TARGET Qt::PrintSupport AND NOT no-png)
|
|
||||||
add_subdirectory(linguist)
|
|
||||||
endif()
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Also force disable clang scanning, it gets very confused.
|
|
||||||
patch -u configure.cmake <<EOF
|
patch -u configure.cmake <<EOF
|
||||||
--- configure.cmake
|
--- configure.cmake
|
||||||
+++ configure.cmake
|
+++ configure.cmake
|
||||||
|
@ -139,21 +217,40 @@ EOF
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -G Ninja -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF ..
|
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
|
||||||
cmake --build . --parallel
|
cmake --build . --parallel
|
||||||
cmake --install .
|
ninja install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
echo "Installing Qt Translations..."
|
echo "Installing Qt Translations..."
|
||||||
|
rm -fr "qttranslations-everywhere-src-$QT"
|
||||||
tar xf "qttranslations-everywhere-src-$QT.tar.xz"
|
tar xf "qttranslations-everywhere-src-$QT.tar.xz"
|
||||||
cd "qttranslations-everywhere-src-$QT"
|
cd "qttranslations-everywhere-src-$QT"
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -G Ninja -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release ..
|
"$INSTALLDIR/bin/qt-configure-module" .. -- -DCMAKE_PREFIX_PATH="$INSTALLDIR"
|
||||||
cmake --build . --parallel
|
cmake --build . --parallel
|
||||||
cmake --install .
|
ninja install
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
|
echo "Building shaderc..."
|
||||||
|
rm -fr "shaderc-$SHADERC"
|
||||||
|
tar xf "shaderc-$SHADERC.tar.gz"
|
||||||
|
cd "shaderc-$SHADERC"
|
||||||
|
cd third_party
|
||||||
|
tar xf "../../shaderc-glslang-$SHADERC_GLSLANG.tar.gz"
|
||||||
|
mv "glslang-$SHADERC_GLSLANG" "glslang"
|
||||||
|
tar xf "../../shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz"
|
||||||
|
mv "SPIRV-Headers-$SHADERC_SPIRVHEADERS" "spirv-headers"
|
||||||
|
tar xf "../../shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz"
|
||||||
|
mv "SPIRV-Tools-$SHADERC_SPIRVTOOLS" "spirv-tools"
|
||||||
|
cd ..
|
||||||
|
patch -p1 < "$SCRIPTDIR/../common/shaderc-changes.patch"
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DSHADERC_SKIP_TESTS=ON -DSHADERC_SKIP_EXAMPLES=ON -DSHADERC_SKIP_COPYRIGHT_CHECK=ON -B build -G Ninja
|
||||||
|
cmake --build build --parallel
|
||||||
|
ninja -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
echo "Cleaning up..."
|
echo "Cleaning up..."
|
||||||
cd ..
|
cd ..
|
||||||
rm -r deps-build
|
rm -r deps-build
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ -n "${GITHUB_ACTIONS}" ]; then
|
|
||||||
echo "Warning: Running this script outside of GitHub Actions isn't recommended."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Prepare the Cache
|
|
||||||
ccache -p
|
|
||||||
ccache -z
|
|
||||||
# Build
|
|
||||||
ninja
|
|
||||||
# Save the Cache
|
|
||||||
ccache -s
|
|
|
@ -8,8 +8,8 @@
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/the-tcpdump-group/libpcap.git",
|
"url": "https://github.com/the-tcpdump-group/libpcap.git",
|
||||||
"tag": "libpcap-1.10.4",
|
"tag": "libpcap-1.10.5",
|
||||||
"commit": "104271ba4a14de6743e43bcf87536786d8fddea4"
|
"commit": "bbcbc9174df3298a854daee2b3e666a4b6e5383a"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cleanup": [
|
"cleanup": [
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
{
|
|
||||||
"name": "libaio",
|
|
||||||
"no-autogen": true,
|
|
||||||
"make-install-args": [
|
|
||||||
"prefix=/app"
|
|
||||||
],
|
|
||||||
"build-options": {
|
|
||||||
"strip": true
|
|
||||||
},
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://pagure.io/libaio.git",
|
|
||||||
"tag": "libaio-0.3.113",
|
|
||||||
"commit": "1b18bfafc6a2f7b9fa2c6be77a95afed8b7be448"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"cleanup": [
|
|
||||||
"/include",
|
|
||||||
"/lib/*.a",
|
|
||||||
"/lib/*.la"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,26 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "sdl2",
|
"name": "sdl2",
|
||||||
"buildsystem": "autotools",
|
"buildsystem": "cmake-ninja",
|
||||||
"no-autogen": true,
|
"builddir": true,
|
||||||
"config-opts": [
|
"config-opts": [
|
||||||
"--disable-dbus",
|
"-DBUILD_SHARED_LIBS=ON",
|
||||||
"--without-x",
|
"-DSDL_SHARED=ON",
|
||||||
"--disable-video-opengl",
|
"-DSDL_STATIC=OFF",
|
||||||
"--disable-video-opengles",
|
"-DSDL_TESTS=OFF"
|
||||||
"--disable-video-vulkan",
|
|
||||||
"--disable-wayland-shared",
|
|
||||||
"--disable-ime",
|
|
||||||
"--disable-oss",
|
|
||||||
"--disable-alsa",
|
|
||||||
"--disable-jack",
|
|
||||||
"--disable-esd",
|
|
||||||
"--disable-pipewire",
|
|
||||||
"--disable-pulseaudio",
|
|
||||||
"--disable-arts",
|
|
||||||
"--disable-nas",
|
|
||||||
"--disable-sndio",
|
|
||||||
"--disable-fusionsound",
|
|
||||||
"--disable-diskaudio"
|
|
||||||
],
|
],
|
||||||
"build-options": {
|
"build-options": {
|
||||||
"strip": true
|
"strip": true
|
||||||
|
@ -28,8 +14,8 @@
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://libsdl.org/release/SDL2-2.28.2.tar.gz",
|
"url": "https://libsdl.org/release/SDL2-2.30.10.tar.gz",
|
||||||
"sha256": "64b1102fa22093515b02ef33dd8739dee1ba57e9dbba6a092942b8bbed1a1c5e"
|
"sha256": "f59adf36a0fcf4c94198e7d3d776c1b3824211ab7aeebeb31fe19836661196aa"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cleanup": [
|
"cleanup": [
|
||||||
|
@ -42,4 +28,3 @@
|
||||||
"/share/aclocal"
|
"/share/aclocal"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "shaderc",
|
||||||
|
"buildsystem": "cmake-ninja",
|
||||||
|
"builddir": true,
|
||||||
|
"config-opts": [
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DSHADERC_SKIP_TESTS=ON",
|
||||||
|
"-DSHADERC_SKIP_EXAMPLES=ON",
|
||||||
|
"-DSHADERC_SKIP_COPYRIGHT_CHECK=ON"
|
||||||
|
],
|
||||||
|
"build-options": {
|
||||||
|
"strip": true
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/google/shaderc.git",
|
||||||
|
"commit": "47a9387ef5b3600d30d84c71ec77a59dc7db46fa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/KhronosGroup/glslang/archive/142052fa30f9eca191aa9dcf65359fcaed09eeec.tar.gz",
|
||||||
|
"sha256": "aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f",
|
||||||
|
"dest": "third_party/glslang"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/KhronosGroup/SPIRV-Headers/archive/5e3ad389ee56fca27c9705d093ae5387ce404df4.tar.gz",
|
||||||
|
"sha256": "5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697",
|
||||||
|
"dest": "third_party/spirv-headers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/KhronosGroup/SPIRV-Tools/archive/dd4b663e13c07fea4fbb3f70c1c91c86731099f7.tar.gz",
|
||||||
|
"sha256": "03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47",
|
||||||
|
"dest": "third_party/spirv-tools"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patch",
|
||||||
|
"path": "../../../common/shaderc-changes.patch"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cleanup": [
|
||||||
|
"/bin",
|
||||||
|
"/include",
|
||||||
|
"/lib/*.a",
|
||||||
|
"/lib/*.la",
|
||||||
|
"/lib/cmake",
|
||||||
|
"/lib/pkgconfig"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"app-id": "net.pcsx2.PCSX2",
|
"app-id": "net.pcsx2.PCSX2",
|
||||||
"runtime": "org.kde.Platform",
|
"runtime": "org.kde.Platform",
|
||||||
"runtime-version": "6.5",
|
"runtime-version": "6.8",
|
||||||
"sdk": "org.kde.Sdk",
|
"sdk": "org.kde.Sdk",
|
||||||
"sdk-extensions": [
|
"sdk-extensions": [
|
||||||
"org.freedesktop.Sdk.Extension.llvm16"
|
"org.freedesktop.Sdk.Extension.llvm18"
|
||||||
],
|
],
|
||||||
"add-extensions": {
|
"add-extensions": {
|
||||||
"org.freedesktop.Platform.ffmpeg-full": {
|
"org.freedesktop.Platform.ffmpeg-full": {
|
||||||
"directory": "lib/ffmpeg",
|
"directory": "lib/ffmpeg",
|
||||||
"version": "22.08",
|
"version": "24.08",
|
||||||
"add-ld-path": ".",
|
"add-ld-path": ".",
|
||||||
"autodownload": true
|
"autodownload": true
|
||||||
}
|
}
|
||||||
|
@ -19,30 +19,39 @@
|
||||||
"--device=all",
|
"--device=all",
|
||||||
"--share=network",
|
"--share=network",
|
||||||
"--share=ipc",
|
"--share=ipc",
|
||||||
"--socket=fallback-x11",
|
"--socket=x11",
|
||||||
"--socket=wayland",
|
|
||||||
"--socket=pulseaudio",
|
"--socket=pulseaudio",
|
||||||
"--filesystem=host:ro",
|
"--talk-name=org.freedesktop.ScreenSaver",
|
||||||
"--talk-name=org.freedesktop.ScreenSaver"
|
"--env=QT_QPA_PLATFORM=xcb"
|
||||||
],
|
],
|
||||||
"modules": [
|
"modules": [
|
||||||
"modules/10-libpcap.json",
|
"modules/10-libpcap.json",
|
||||||
"modules/11-libaio.json",
|
|
||||||
"modules/20-sdl2.json",
|
"modules/20-sdl2.json",
|
||||||
"modules/21-libbacktrace.json",
|
"modules/21-libbacktrace.json",
|
||||||
|
"modules/22-shaderc.json",
|
||||||
{
|
{
|
||||||
"name": "pcsx2",
|
"name": "pcsx2",
|
||||||
"buildsystem": "simple",
|
"buildsystem": "cmake-ninja",
|
||||||
|
"builddir": true,
|
||||||
|
"no-make-install": true,
|
||||||
"build-options": {
|
"build-options": {
|
||||||
"strip": false,
|
"strip": false,
|
||||||
"no-debuginfo": true,
|
"no-debuginfo": true,
|
||||||
"env": {
|
"cflags": "",
|
||||||
"DEPS_PREFIX": "/app",
|
"cflags-override": true,
|
||||||
"COMPILER": "clang",
|
"cxxflags": "",
|
||||||
"CLANG_PATH": "/usr/lib/sdk/llvm16/bin/clang",
|
"cxxflags-override": true,
|
||||||
"CLANGXX_PATH": "/usr/lib/sdk/llvm16/bin/clang++",
|
"config-opts": [
|
||||||
"ADDITIONAL_CMAKE_ARGS": "-DUSE_LINKED_FFMPEG=ON"
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
}
|
"-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON",
|
||||||
|
"-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm18/bin/clang",
|
||||||
|
"-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm18/bin/clang++",
|
||||||
|
"-DCMAKE_EXE_LINKER_FLAGS_INIT=-fuse-ld=lld",
|
||||||
|
"-DCMAKE_MODULE_LINKER_FLAGS_INIT=-fuse-ld=lld",
|
||||||
|
"-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld",
|
||||||
|
"-DUSE_LINKED_FFMPEG=ON",
|
||||||
|
"-DDISABLE_ADVANCE_SIMD=TRUE"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
|
@ -50,17 +59,15 @@
|
||||||
"path": "../../../../.."
|
"path": "../../../../.."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"build-commands": [
|
|
||||||
".github/workflows/scripts/linux/generate-cmake-qt.sh",
|
|
||||||
"cd build && ../.github/workflows/scripts/linux/compile.sh && cd ..",
|
|
||||||
"cp -a build/bin ${FLATPAK_DEST}",
|
|
||||||
"cd build && ninja unittests && cd .."
|
|
||||||
],
|
|
||||||
"post-install": [
|
"post-install": [
|
||||||
"install -Dm644 bin/resources/icons/AppIconLarge.png ${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/net.pcsx2.PCSX2.png",
|
"cp -a bin \"${FLATPAK_DEST}\"",
|
||||||
"install -Dm644 .github/workflows/scripts/linux/pcsx2-qt.desktop ${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop",
|
"install -Dm644 \"${FLATPAK_BUILDER_BUILDDIR}/bin/resources/icons/AppIconLarge.png\" \"${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/net.pcsx2.PCSX2.png\"",
|
||||||
"desktop-file-edit --set-key=Icon --set-value=net.pcsx2.PCSX2 ${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop",
|
"install -Dm644 \"${FLATPAK_BUILDER_BUILDDIR}/.github/workflows/scripts/linux/pcsx2-qt.desktop\" \"${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop\"",
|
||||||
"install -Dm644 .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml ${FLATPAK_DEST}/share/metainfo/net.pcsx2.PCSX2.metainfo.xml"
|
"desktop-file-edit --set-key=Icon --set-value=net.pcsx2.PCSX2 \"${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop\"",
|
||||||
|
"${FLATPAK_BUILDER_BUILDDIR}/.github/workflows/scripts/linux/generate-metainfo.sh \"${FLATPAK_BUILDER_BUILDDIR}/net.pcsx2.PCSX2.metainfo.xml\"",
|
||||||
|
"cat \"${FLATPAK_BUILDER_BUILDDIR}/net.pcsx2.PCSX2.metainfo.xml\"",
|
||||||
|
"install -Dm644 \"${FLATPAK_BUILDER_BUILDDIR}/net.pcsx2.PCSX2.metainfo.xml\" \"${FLATPAK_DEST}/share/metainfo/net.pcsx2.PCSX2.metainfo.xml\"",
|
||||||
|
"mkdir -p \"${FLATPAK_DEST}/lib/ffmpeg\""
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
function retry_command {
|
|
||||||
# Package servers tend to be unreliable at times..
|
|
||||||
# Retry a bunch of times.
|
|
||||||
local RETRIES=10
|
|
||||||
|
|
||||||
for i in $(seq 1 "$RETRIES"); do
|
|
||||||
"$@" && break
|
|
||||||
if [ "$i" == "$RETRIES" ]; then
|
|
||||||
echo "Command \"$@\" failed after ${RETRIES} retries."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [[ -z "${DEPS_PREFIX}" ]]; then
|
|
||||||
echo "DEPS_PREFIX is not set."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Using build dependencies from: ${DEPS_PREFIX}"
|
|
||||||
|
|
||||||
if [ "${COMPILER}" = "clang" ]; then
|
|
||||||
if [[ -z "${CLANG_PATH}" ]] || [[ -z "${CLANGXX_PATH}" ]]; then
|
|
||||||
echo "CLANG_PATH or CLANGXX_PATH is not set."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Using clang toolchain"
|
|
||||||
cat > "clang-toolchain.cmake" << EOF
|
|
||||||
set(CMAKE_C_COMPILER "${CLANG_PATH}")
|
|
||||||
set(CMAKE_CXX_COMPILER "${CLANGXX_PATH}")
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld")
|
|
||||||
set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld")
|
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld")
|
|
||||||
EOF
|
|
||||||
ADDITIONAL_CMAKE_ARGS="$ADDITIONAL_CMAKE_ARGS -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_TOOLCHAIN_FILE=clang-toolchain.cmake"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Additional CMake Args - ${ADDITIONAL_CMAKE_ARGS}"
|
|
||||||
|
|
||||||
# Generate CMake into ./build
|
|
||||||
# DISABLE_ADVANCE_SIMD is needed otherwise we end up doing -march=native.
|
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
cmake \
|
|
||||||
-B build \
|
|
||||||
-G Ninja \
|
|
||||||
$ADDITIONAL_CMAKE_ARGS \
|
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DQT_BUILD=ON \
|
|
||||||
-DCUBEB_API=ON \
|
|
||||||
-DX11_API=ON \
|
|
||||||
-DWAYLAND_API=ON \
|
|
||||||
-DENABLE_SETCAP=OFF \
|
|
||||||
-DCMAKE_PREFIX_PATH="${DEPS_PREFIX}" \
|
|
||||||
-DUSE_SYSTEM_SDL2=ON \
|
|
||||||
-DUSE_SYSTEM_ZSTD=OFF \
|
|
||||||
-DDISABLE_ADVANCE_SIMD=TRUE
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ if [[ $# -lt 1 ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OUTFILE=$1
|
OUTFILE=$1
|
||||||
GIT_DATE=$(git log -1 --pretty=%cd --date=short)
|
GIT_DATE=$(git log -1 --pretty=%cd --date=iso8601)
|
||||||
GIT_VERSION=$(git tag --points-at HEAD)
|
GIT_VERSION=$(git tag --points-at HEAD)
|
||||||
GIT_HASH=$(git rev-parse HEAD)
|
GIT_HASH=$(git rev-parse HEAD)
|
||||||
|
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
|
||||||
source "$SCRIPTDIR/functions.sh"
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
ARCH=x86_64
|
|
||||||
KDE_BRANCH=6.5
|
|
||||||
BRANCH=22.08
|
|
||||||
FLAT_MANAGER_CLIENT_DIR="$HOME/.local/bin"
|
|
||||||
|
|
||||||
# Build packages. Mostly needed for flat-manager-client.
|
|
||||||
declare -a BUILD_PACKAGES=(
|
|
||||||
"flatpak"
|
|
||||||
"flatpak-builder"
|
|
||||||
"appstream-util"
|
|
||||||
"python3-aiohttp"
|
|
||||||
"python3-tenacity"
|
|
||||||
"python3-gi"
|
|
||||||
"gobject-introspection"
|
|
||||||
"libappstream-glib8"
|
|
||||||
"libappstream-glib-dev"
|
|
||||||
"libappstream-dev"
|
|
||||||
"gir1.2-ostree-1.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Flatpak runtimes and SDKs.
|
|
||||||
declare -a FLATPAK_PACKAGES=(
|
|
||||||
"org.kde.Platform/${ARCH}/${KDE_BRANCH}"
|
|
||||||
"org.kde.Sdk/${ARCH}/${KDE_BRANCH}"
|
|
||||||
"org.freedesktop.Platform.ffmpeg-full/${ARCH}/${BRANCH}"
|
|
||||||
"org.freedesktop.Sdk.Extension.llvm16/${ARCH}/${BRANCH}"
|
|
||||||
"org.freedesktop.appstream-glib/${ARCH}/stable"
|
|
||||||
)
|
|
||||||
|
|
||||||
retry_command sudo apt-get -qq update
|
|
||||||
|
|
||||||
# Install packages needed for building
|
|
||||||
echo "Will install the following packages for building - ${BUILD_PACKAGES[*]}"
|
|
||||||
retry_command sudo apt-get -y install "${BUILD_PACKAGES[@]}"
|
|
||||||
|
|
||||||
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
|
||||||
|
|
||||||
# Install packages needed for building
|
|
||||||
echo "Will install the following packages for building - ${FLATPAK_PACKAGES[*]}"
|
|
||||||
retry_command sudo flatpak -y install "${FLATPAK_PACKAGES[@]}"
|
|
||||||
|
|
||||||
echo "Downloading flat-manager-client"
|
|
||||||
mkdir -p "$FLAT_MANAGER_CLIENT_DIR"
|
|
||||||
pushd "$FLAT_MANAGER_CLIENT_DIR"
|
|
||||||
aria2c -Z "https://raw.githubusercontent.com/flatpak/flat-manager/9401efbdc0d6bd489507d8401c567ba219d735d5/flat-manager-client"
|
|
||||||
chmod +x flat-manager-client
|
|
||||||
echo "$FLAT_MANAGER_CLIENT_DIR" >> $GITHUB_PATH
|
|
||||||
popd
|
|
|
@ -1,83 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
|
||||||
source "$SCRIPTDIR/functions.sh"
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Packages - Build and Qt
|
|
||||||
declare -a BUILD_PACKAGES=(
|
|
||||||
"build-essential"
|
|
||||||
"g++"
|
|
||||||
"git"
|
|
||||||
"cmake"
|
|
||||||
"ccache"
|
|
||||||
"ninja-build"
|
|
||||||
"patchelf"
|
|
||||||
"libfuse2"
|
|
||||||
"libglib2.0-dev"
|
|
||||||
"libfontconfig1-dev"
|
|
||||||
"libharfbuzz-dev"
|
|
||||||
"libjpeg-dev"
|
|
||||||
"libpng-dev"
|
|
||||||
"libfreetype-dev"
|
|
||||||
"libinput-dev"
|
|
||||||
"libxcb-*-dev"
|
|
||||||
"libxkbcommon-dev"
|
|
||||||
"libxkbcommon-x11-dev"
|
|
||||||
"libxrender-dev"
|
|
||||||
"libwayland-dev"
|
|
||||||
"libgl1-mesa-dev"
|
|
||||||
"libegl-dev"
|
|
||||||
"libegl1-mesa-dev"
|
|
||||||
"libgl1-mesa-dev"
|
|
||||||
"libssl-dev"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Packages - PCSX2
|
|
||||||
declare -a PCSX2_PACKAGES=(
|
|
||||||
"extra-cmake-modules"
|
|
||||||
"libaio-dev"
|
|
||||||
"libasound2-dev"
|
|
||||||
"libbz2-dev"
|
|
||||||
"libcurl4-openssl-dev"
|
|
||||||
"libegl1-mesa-dev"
|
|
||||||
"libgl1-mesa-dev"
|
|
||||||
"libgtk-3-dev"
|
|
||||||
"libharfbuzz-dev"
|
|
||||||
"libjpeg-dev"
|
|
||||||
"liblzma-dev"
|
|
||||||
"libpcap0.8-dev"
|
|
||||||
"libpng-dev"
|
|
||||||
"libpulse-dev"
|
|
||||||
"librsvg2-dev"
|
|
||||||
"libsamplerate0-dev"
|
|
||||||
"libudev-dev"
|
|
||||||
"libx11-xcb-dev"
|
|
||||||
"libavcodec-dev"
|
|
||||||
"libavformat-dev"
|
|
||||||
"libavutil-dev"
|
|
||||||
"libswresample-dev"
|
|
||||||
"libswscale-dev"
|
|
||||||
"pkg-config"
|
|
||||||
"zlib1g-dev"
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ "${COMPILER}" = "clang" ]; then
|
|
||||||
BUILD_PACKAGES+=("llvm-16" "lld-16" "clang-16")
|
|
||||||
|
|
||||||
# Ubuntu 22.04 doesn't ship with LLVM 16, so we need to pull it from the llvm.org repos.
|
|
||||||
retry_command wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-add-repository -n 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main'
|
|
||||||
fi
|
|
||||||
|
|
||||||
retry_command sudo apt-get -qq update && break
|
|
||||||
|
|
||||||
# Install packages needed for building
|
|
||||||
echo "Will install the following packages for building - ${BUILD_PACKAGES[*]}"
|
|
||||||
retry_command sudo apt-get -y install "${BUILD_PACKAGES[@]}"
|
|
||||||
|
|
||||||
# Install packages needed by pcsx2
|
|
||||||
PCSX2_PACKAGES=("${PCSX2_PACKAGES[@]}")
|
|
||||||
echo "Will install the following packages for pcsx2 - ${PCSX2_PACKAGES[*]}"
|
|
||||||
retry_command sudo apt-get -y install "${PCSX2_PACKAGES[@]}"
|
|
|
@ -1,33 +1,44 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Uses the AppStream standard https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html -->
|
||||||
<component type="desktop">
|
<component type="desktop">
|
||||||
<id>net.pcsx2.PCSX2</id>
|
<id>net.pcsx2.PCSX2</id>
|
||||||
<launchable type="desktop-id">net.pcsx2.PCSX2.desktop</launchable>
|
<launchable type="desktop-id">net.pcsx2.PCSX2.desktop</launchable>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
<project_license>GPL-3.0</project_license>
|
<project_license>GPL-3.0+</project_license>
|
||||||
<name>PCSX2</name>
|
<name>PCSX2</name>
|
||||||
<developer_name>PCSX2</developer_name>
|
<developer_name>PCSX2</developer_name>
|
||||||
<summary>PlayStation 2 Emulator</summary>
|
<summary>PlayStation 2 Emulator</summary>
|
||||||
<description>
|
<description>
|
||||||
<p>PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your PC, with many additional features and benefits.</p>
|
<p>PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers, and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your PC, with many additional features and benefits.</p>
|
||||||
<p>PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.</p>
|
<p>PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.</p>
|
||||||
</description>
|
</description>
|
||||||
<url type="homepage">https://pcsx2.net/</url>
|
<url type="homepage">https://pcsx2.net/</url>
|
||||||
<url type="bugtracker">https://github.com/PCSX2/pcsx2/issues</url>
|
<url type="bugtracker">https://github.com/PCSX2/pcsx2/issues</url>
|
||||||
<url type="donation">https://github.com/sponsors/PCSX2</url>
|
<url type="donation">https://github.com/sponsors/PCSX2</url>
|
||||||
<url type="faq">https://pcsx2.net/docs/</url>
|
<url type="faq">https://pcsx2.net/docs/</url>
|
||||||
<url type="help">https://discord.com/invite/TCz3t9k</url>
|
<url type="help">https://pcsx2.net/discord</url>
|
||||||
<url type="translate">https://crowdin.com/project/pcsx2-emulator</url>
|
<url type="translate">https://crowdin.com/project/pcsx2-emulator</url>
|
||||||
<url type="vcs-browser">https://github.com/PCSX2/pcsx2</url>
|
<url type="contact">https://mastodon.social/@PCSX2</url>
|
||||||
<screenshots>
|
<screenshots>
|
||||||
<screenshot type="default">
|
<screenshot type="default">
|
||||||
<image>https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot1.png</image>
|
<image>
|
||||||
|
https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot1.png
|
||||||
|
</image>
|
||||||
|
<caption>
|
||||||
|
The main PCSX2 Qt interface
|
||||||
|
</caption>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
<screenshot>
|
<screenshot>
|
||||||
<image>https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot2.png</image>
|
<image>
|
||||||
|
https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot2.png
|
||||||
|
</image>
|
||||||
|
<caption>
|
||||||
|
PCSX2 running a game
|
||||||
|
</caption>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
</screenshots>
|
</screenshots>
|
||||||
<content_rating type="oars-1.1"/>
|
<content_rating type="oars-1.1"/>
|
||||||
<update_contact>stenzek_AT_gmail.com</update_contact>
|
<update_contact>pcsx2_AT_pcsx2.net</update_contact>
|
||||||
<releases>
|
<releases>
|
||||||
<release version="@GIT_VERSION@" date="@GIT_DATE@" />
|
<release version="@GIT_VERSION@" date="@GIT_DATE@" />
|
||||||
</releases>
|
</releases>
|
||||||
|
|
|
@ -0,0 +1,371 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
merge_binaries() {
|
||||||
|
X86DIR=$1
|
||||||
|
ARMDIR=$2
|
||||||
|
echo "Merging ARM64 binaries from $ARMDIR into fat binaries at $X86DIR..."
|
||||||
|
|
||||||
|
IFS="
|
||||||
|
"
|
||||||
|
pushd "$X86DIR"
|
||||||
|
for X86BIN in $(find . -type f \( -name '*.dylib' -o -name '*.a' -o -perm +111 \)); do
|
||||||
|
if file "$X86DIR/$X86BIN" | grep "Mach-O " >/dev/null; then
|
||||||
|
ARMBIN="${ARMDIR}/${X86BIN}"
|
||||||
|
echo "Merge $ARMBIN to $X86BIN..."
|
||||||
|
lipo -create "$X86BIN" "$ARMBIN" -o "$X86BIN"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
echo "Syntax: $0 <output directory>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The bundled ffmpeg has a lot of things disabled to reduce code size.
|
||||||
|
# Users may want to use system ffmpeg for additional features
|
||||||
|
: ${BUILD_FFMPEG:=1}
|
||||||
|
|
||||||
|
export MACOSX_DEPLOYMENT_TARGET=11.0
|
||||||
|
|
||||||
|
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
||||||
|
SCRIPTDIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
|
||||||
|
INSTALLDIR="$1"
|
||||||
|
if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||||
|
INSTALLDIR="$PWD/$INSTALLDIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
FREETYPE=2.13.3
|
||||||
|
HARFBUZZ=10.0.1
|
||||||
|
SDL=SDL2-2.30.10
|
||||||
|
ZSTD=1.5.6
|
||||||
|
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||||
|
LIBPNG=1.6.44
|
||||||
|
LIBJPEG=9f
|
||||||
|
LIBWEBP=1.4.0
|
||||||
|
FFMPEG=6.0
|
||||||
|
MOLTENVK=1.2.9
|
||||||
|
QT=6.7.2
|
||||||
|
|
||||||
|
SHADERC=2024.1
|
||||||
|
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||||
|
SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
|
||||||
|
SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||||
|
|
||||||
|
mkdir -p deps-build
|
||||||
|
cd deps-build
|
||||||
|
|
||||||
|
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||||
|
export LDFLAGS="-L$INSTALLDIR/lib $LDFLAGS"
|
||||||
|
export CFLAGS="-I$INSTALLDIR/include $CFLAGS"
|
||||||
|
export CXXFLAGS="-I$INSTALLDIR/include $CXXFLAGS"
|
||||||
|
CMAKE_COMMON=(
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
-DCMAKE_SHARED_LINKER_FLAGS="-dead_strip -dead_strip_dylibs"
|
||||||
|
-DCMAKE_PREFIX_PATH="$INSTALLDIR"
|
||||||
|
-DCMAKE_INSTALL_PREFIX="$INSTALLDIR"
|
||||||
|
-DCMAKE_INSTALL_NAME_DIR='$<INSTALL_PREFIX>/lib'
|
||||||
|
)
|
||||||
|
CMAKE_ARCH_X64=-DCMAKE_OSX_ARCHITECTURES="x86_64"
|
||||||
|
CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
|
||||||
|
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
||||||
|
|
||||||
|
cat > SHASUMS <<EOF
|
||||||
|
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
|
||||||
|
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
|
||||||
|
f59adf36a0fcf4c94198e7d3d776c1b3824211ab7aeebeb31fe19836661196aa $SDL.tar.gz
|
||||||
|
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||||
|
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||||
|
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
|
||||||
|
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
|
||||||
|
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
|
||||||
|
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
|
||||||
|
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
|
||||||
|
c5f22a5e10fb162895ded7de0963328e7307611c688487b5d152c9ee64767599 qtbase-everywhere-src-$QT.tar.xz
|
||||||
|
e1a1d8785fae67d16ad0a443b01d5f32663a6b68d275f1806ebab257485ce5d6 qtimageformats-everywhere-src-$QT.tar.xz
|
||||||
|
fb0d1286a35be3583fee34aeb5843c94719e07193bdf1d4d8b0dc14009caef01 qtsvg-everywhere-src-$QT.tar.xz
|
||||||
|
58e855ad1b2533094726c8a425766b63a04a0eede2ed85086860e54593aa4b2a qttools-everywhere-src-$QT.tar.xz
|
||||||
|
9845780b5dc1b7279d57836db51aeaf2e4a1160c42be09750616f39157582ca9 qttranslations-everywhere-src-$QT.tar.xz
|
||||||
|
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
|
||||||
|
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||||
|
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||||
|
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||||
|
EOF
|
||||||
|
|
||||||
|
curl -C - -L \
|
||||||
|
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
|
||||||
|
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
|
||||||
|
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
||||||
|
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||||
|
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||||
|
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||||
|
-O "https://ijg.org/files/jpegsrc.v$LIBJPEG.tar.gz" \
|
||||||
|
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||||
|
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
||||||
|
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
|
||||||
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||||
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||||
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
||||||
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
||||||
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
||||||
|
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
|
||||||
|
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||||
|
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||||
|
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz"
|
||||||
|
|
||||||
|
shasum -a 256 --check SHASUMS
|
||||||
|
|
||||||
|
echo "Installing SDL..."
|
||||||
|
rm -fr "$SDL"
|
||||||
|
tar xf "$SDL.tar.gz"
|
||||||
|
cd "$SDL"
|
||||||
|
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON
|
||||||
|
make -C build "-j$NPROCS"
|
||||||
|
make -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
if [ "$BUILD_FFMPEG" -ne 0 ]; then
|
||||||
|
echo "Installing FFmpeg..."
|
||||||
|
rm -fr "ffmpeg-$FFMPEG"
|
||||||
|
tar xf "ffmpeg-$FFMPEG.tar.xz"
|
||||||
|
cd "ffmpeg-$FFMPEG"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
LDFLAGS="-dead_strip $LDFLAGS" CFLAGS="-Os $CFLAGS" CXXFLAGS="-Os $CXXFLAGS" \
|
||||||
|
../configure --prefix="$INSTALLDIR" \
|
||||||
|
--enable-cross-compile --arch=x86_64 --cc='clang -arch x86_64' --cxx='clang++ -arch x86_64' --disable-x86asm \
|
||||||
|
--disable-all --disable-autodetect --disable-static --enable-shared \
|
||||||
|
--enable-avcodec --enable-avformat --enable-avutil --enable-swresample --enable-swscale \
|
||||||
|
--enable-audiotoolbox --enable-videotoolbox \
|
||||||
|
--enable-encoder=ffv1,qtrle,pcm_s16be,pcm_s16le,*_at,*_videotoolbox \
|
||||||
|
--enable-muxer=avi,matroska,mov,mp3,mp4,wav \
|
||||||
|
--enable-protocol=file
|
||||||
|
make "-j$NPROCS"
|
||||||
|
cd ..
|
||||||
|
mkdir build-arm64
|
||||||
|
cd build-arm64
|
||||||
|
LDFLAGS="-dead_strip $LDFLAGS" CFLAGS="-Os $CFLAGS" CXXFLAGS="-Os $CXXFLAGS" \
|
||||||
|
../configure --prefix="$INSTALLDIR" \
|
||||||
|
--enable-cross-compile --arch=arm64 --cc='clang -arch arm64' --cxx='clang++ -arch arm64' --disable-x86asm \
|
||||||
|
--disable-all --disable-autodetect --disable-static --enable-shared \
|
||||||
|
--enable-avcodec --enable-avformat --enable-avutil --enable-swresample --enable-swscale \
|
||||||
|
--enable-audiotoolbox --enable-videotoolbox \
|
||||||
|
--enable-encoder=ffv1,qtrle,pcm_s16be,pcm_s16le,*_at,*_videotoolbox \
|
||||||
|
--enable-muxer=avi,matroska,mov,mp3,mp4,wav \
|
||||||
|
--enable-protocol=file
|
||||||
|
make "-j$NPROCS"
|
||||||
|
cd ..
|
||||||
|
merge_binaries $(realpath build) $(realpath build-arm64)
|
||||||
|
cd build
|
||||||
|
make install
|
||||||
|
cd ../..
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing Zstd..."
|
||||||
|
rm -fr "zstd-$ZSTD"
|
||||||
|
tar xf "zstd-$ZSTD.tar.gz"
|
||||||
|
cd "zstd-$ZSTD"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_X64" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_PROGRAMS=OFF -B build-dir build/cmake
|
||||||
|
make -C build-dir "-j$NPROCS"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_ARM64" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_PROGRAMS=OFF -B build-dir-arm64 build/cmake
|
||||||
|
make -C build-dir-arm64 "-j$NPROCS"
|
||||||
|
merge_binaries $(realpath build-dir) $(realpath build-dir-arm64)
|
||||||
|
make -C build-dir install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Installing LZ4..."
|
||||||
|
rm -fr "lz4-$LZ4"
|
||||||
|
tar xf "$LZ4.tar.gz"
|
||||||
|
cd "lz4-$LZ4"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_X64" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -B build-dir build/cmake
|
||||||
|
make -C build-dir "-j$NPROCS"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_ARM64" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -B build-dir-arm64 build/cmake
|
||||||
|
make -C build-dir-arm64 "-j$NPROCS"
|
||||||
|
merge_binaries $(realpath build-dir) $(realpath build-dir-arm64)
|
||||||
|
make -C build-dir install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Installing libpng..."
|
||||||
|
rm -fr "libpng-$LIBPNG"
|
||||||
|
tar xf "libpng-$LIBPNG.tar.xz"
|
||||||
|
cd "libpng-$LIBPNG"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_X64" -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -DPNG_FRAMEWORK=OFF -B build
|
||||||
|
make -C build "-j$NPROCS"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_ARM64" -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -DPNG_FRAMEWORK=OFF -DPNG_ARM_NEON=on -B build-arm64
|
||||||
|
make -C build-arm64 "-j$NPROCS"
|
||||||
|
merge_binaries $(realpath build) $(realpath build-arm64)
|
||||||
|
make -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Installing libjpeg..."
|
||||||
|
rm -fr "jpeg-$LIBJPEG"
|
||||||
|
tar xf "jpegsrc.v$LIBJPEG.tar.gz"
|
||||||
|
cd "jpeg-$LIBJPEG"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
../configure --prefix="$INSTALLDIR" --disable-static --enable-shared --host="x86_64-apple-darwin" CFLAGS="-arch x86_64"
|
||||||
|
make "-j$NPROCS"
|
||||||
|
cd ..
|
||||||
|
mkdir build-arm64
|
||||||
|
cd build-arm64
|
||||||
|
../configure --prefix="$INSTALLDIR" --disable-static --enable-shared --host="aarch64-apple-darwin" CFLAGS="-arch arm64"
|
||||||
|
make "-j$NPROCS"
|
||||||
|
cd ..
|
||||||
|
merge_binaries $(realpath build) $(realpath build-arm64)
|
||||||
|
make -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Installing WebP..."
|
||||||
|
rm -fr "libwebp-$LIBWEBP"
|
||||||
|
tar xf "libwebp-$LIBWEBP.tar.gz"
|
||||||
|
cd "libwebp-$LIBWEBP"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_X64" -B build \
|
||||||
|
-DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF \
|
||||||
|
-DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON
|
||||||
|
make -C build "-j$NPROCS"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_ARM64" -B build-arm64 \
|
||||||
|
-DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF \
|
||||||
|
-DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON
|
||||||
|
make -C build-arm64 "-j$NPROCS"
|
||||||
|
merge_binaries $(realpath build) $(realpath build-arm64)
|
||||||
|
make -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Building FreeType without HarfBuzz..."
|
||||||
|
rm -fr "freetype-$FREETYPE"
|
||||||
|
tar xf "freetype-$FREETYPE.tar.xz"
|
||||||
|
cd "freetype-$FREETYPE"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B build
|
||||||
|
cmake --build build --parallel
|
||||||
|
cmake --install build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Building HarfBuzz..."
|
||||||
|
rm -fr "harfbuzz-$HARFBUZZ"
|
||||||
|
tar xf "harfbuzz-$HARFBUZZ.tar.gz"
|
||||||
|
cd "harfbuzz-$HARFBUZZ"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -B build
|
||||||
|
cmake --build build --parallel
|
||||||
|
cmake --install build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Building FreeType with HarfBuzz..."
|
||||||
|
rm -fr "freetype-$FREETYPE"
|
||||||
|
tar xf "freetype-$FREETYPE.tar.xz"
|
||||||
|
cd "freetype-$FREETYPE"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_REQUIRE_HARFBUZZ=TRUE -B build
|
||||||
|
cmake --build build --parallel
|
||||||
|
cmake --install build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# MoltenVK already builds universal binaries, nothing special to do here.
|
||||||
|
echo "Installing MoltenVK..."
|
||||||
|
rm -fr "MoltenVK-${MOLTENVK}"
|
||||||
|
tar xf "v$MOLTENVK.tar.gz"
|
||||||
|
cd "MoltenVK-${MOLTENVK}"
|
||||||
|
./fetchDependencies --macos
|
||||||
|
make macos
|
||||||
|
cp Package/Latest/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib "$INSTALLDIR/lib/"
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Installing Qt Base..."
|
||||||
|
rm -fr "qtbase-everywhere-src-$QT"
|
||||||
|
tar xf "qtbase-everywhere-src-$QT.tar.xz"
|
||||||
|
cd "qtbase-everywhere-src-$QT"
|
||||||
|
# since we don't have a direct reference to QtSvg, it doesn't deployed directly from the main binary
|
||||||
|
# (only indirectly from iconengines), and the libqsvg.dylib imageformat plugin does not get deployed.
|
||||||
|
# We could run macdeployqt twice, but that's even more janky than patching it.
|
||||||
|
patch -u src/tools/macdeployqt/shared/shared.cpp <<EOF
|
||||||
|
--- shared.cpp
|
||||||
|
+++ shared.cpp
|
||||||
|
@@ -1119,14 +1119,8 @@
|
||||||
|
addPlugins(QStringLiteral("networkinformation"));
|
||||||
|
}
|
||||||
|
|
||||||
|
- // All image formats (svg if QtSvg is used)
|
||||||
|
- const bool usesSvg = deploymentInfo.containsModule("Svg", libInfix);
|
||||||
|
- addPlugins(QStringLiteral("imageformats"), [usesSvg](const QString &lib) {
|
||||||
|
- if (lib.contains(QStringLiteral("qsvg")) && !usesSvg)
|
||||||
|
- return false;
|
||||||
|
- return true;
|
||||||
|
- });
|
||||||
|
-
|
||||||
|
+ // All image formats
|
||||||
|
+ addPlugins(QStringLiteral("imageformats"));
|
||||||
|
addPlugins(QStringLiteral("iconengines"));
|
||||||
|
|
||||||
|
// Platforminputcontext plugins if QtGui is in use
|
||||||
|
EOF
|
||||||
|
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
|
||||||
|
make -C build "-j$NPROCS"
|
||||||
|
make -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Installing Qt SVG..."
|
||||||
|
rm -fr "qtsvg-everywhere-src-$QT"
|
||||||
|
tar xf "qtsvg-everywhere-src-$QT.tar.xz"
|
||||||
|
cd "qtsvg-everywhere-src-$QT"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL"
|
||||||
|
make "-j$NPROCS"
|
||||||
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo "Installing Qt Image Formats..."
|
||||||
|
rm -fr "qtimageformats-everywhere-src-$QT"
|
||||||
|
tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
|
||||||
|
cd "qtimageformats-everywhere-src-$QT"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_system_webp=ON
|
||||||
|
make "-j$NPROCS"
|
||||||
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo "Installing Qt Tools..."
|
||||||
|
rm -fr "qttools-everywhere-src-$QT"
|
||||||
|
tar xf "qttools-everywhere-src-$QT.tar.xz"
|
||||||
|
cd "qttools-everywhere-src-$QT"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
|
||||||
|
make "-j$NPROCS"
|
||||||
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo "Building shaderc..."
|
||||||
|
rm -fr "shaderc-$SHADERC"
|
||||||
|
tar xf "shaderc-$SHADERC.tar.gz"
|
||||||
|
cd "shaderc-$SHADERC"
|
||||||
|
cd third_party
|
||||||
|
tar xf "../../shaderc-glslang-$SHADERC_GLSLANG.tar.gz"
|
||||||
|
mv "glslang-$SHADERC_GLSLANG" "glslang"
|
||||||
|
tar xf "../../shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz"
|
||||||
|
mv "SPIRV-Headers-$SHADERC_SPIRVHEADERS" "spirv-headers"
|
||||||
|
tar xf "../../shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz"
|
||||||
|
mv "SPIRV-Tools-$SHADERC_SPIRVTOOLS" "spirv-tools"
|
||||||
|
cd ..
|
||||||
|
patch -p1 < "$SCRIPTDIR/../common/shaderc-changes.patch"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSHADERC_SKIP_TESTS=ON -DSHADERC_SKIP_EXAMPLES=ON -DSHADERC_SKIP_COPYRIGHT_CHECK=ON -B build
|
||||||
|
make -C build "-j$NPROCS"
|
||||||
|
make -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Installing Qt Translations..."
|
||||||
|
rm -fr "qttranslations-everywhere-src-$QT"
|
||||||
|
tar xf "qttranslations-everywhere-src-$QT.tar.xz"
|
||||||
|
cd "qttranslations-everywhere-src-$QT"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL"
|
||||||
|
make "-j$NPROCS"
|
||||||
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo "Cleaning up..."
|
||||||
|
cd ..
|
||||||
|
rm -rf deps-build
|
|
@ -2,238 +2,328 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
export MACOSX_DEPLOYMENT_TARGET=10.14
|
if [ "$#" -ne 1 ]; then
|
||||||
|
echo "Syntax: $0 <output directory>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The bundled ffmpeg has a lot of things disabled to reduce code size.
|
||||||
|
# Users may want to use system ffmpeg for additional features
|
||||||
|
: ${BUILD_FFMPEG:=1}
|
||||||
|
|
||||||
|
export MACOSX_DEPLOYMENT_TARGET=11.0
|
||||||
|
|
||||||
INSTALLDIR="$HOME/deps"
|
|
||||||
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
||||||
SDL=SDL2-2.28.2
|
SCRIPTDIR=$(realpath $(dirname "${BASH_SOURCE[0]}"))
|
||||||
PNG=1.6.37
|
INSTALLDIR="$1"
|
||||||
JPG=9e
|
if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||||
FFMPEG=6.0
|
INSTALLDIR="$PWD/$INSTALLDIR"
|
||||||
QT=6.4.3 # Currently stuck on Qt 6.4 due to 6.5 requiring macOS 11.0.
|
fi
|
||||||
|
|
||||||
mkdir deps-build
|
FREETYPE=2.13.3
|
||||||
|
HARFBUZZ=10.0.1
|
||||||
|
SDL=SDL2-2.30.10
|
||||||
|
ZSTD=1.5.6
|
||||||
|
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||||
|
LIBPNG=1.6.44
|
||||||
|
LIBJPEG=9f
|
||||||
|
LIBWEBP=1.4.0
|
||||||
|
FFMPEG=6.0
|
||||||
|
MOLTENVK=1.2.9
|
||||||
|
QT=6.7.2
|
||||||
|
|
||||||
|
SHADERC=2024.1
|
||||||
|
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||||
|
SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
|
||||||
|
SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||||
|
|
||||||
|
mkdir -p deps-build
|
||||||
cd deps-build
|
cd deps-build
|
||||||
|
|
||||||
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
|
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||||
export LDFLAGS="-L$INSTALLDIR/lib -dead_strip $LDFLAGS"
|
export LDFLAGS="-L$INSTALLDIR/lib $LDFLAGS"
|
||||||
export CFLAGS="-I$INSTALLDIR/include -Os $CFLAGS"
|
export CFLAGS="-I$INSTALLDIR/include $CFLAGS"
|
||||||
export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS"
|
export CXXFLAGS="-I$INSTALLDIR/include $CXXFLAGS"
|
||||||
|
CMAKE_COMMON=(
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
-DCMAKE_SHARED_LINKER_FLAGS="-dead_strip -dead_strip_dylibs"
|
||||||
|
-DCMAKE_PREFIX_PATH="$INSTALLDIR"
|
||||||
|
-DCMAKE_INSTALL_PREFIX="$INSTALLDIR"
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES="x86_64"
|
||||||
|
-DCMAKE_INSTALL_NAME_DIR='$<INSTALL_PREFIX>/lib'
|
||||||
|
)
|
||||||
|
|
||||||
cat > SHASUMS <<EOF
|
cat > SHASUMS <<EOF
|
||||||
64b1102fa22093515b02ef33dd8739dee1ba57e9dbba6a092942b8bbed1a1c5e $SDL.tar.gz
|
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
|
||||||
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-$PNG.tar.xz
|
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
|
||||||
4077d6a6a75aeb01884f708919d25934c93305e49f7e3f36db9129320e6f4f3d jpegsrc.v$JPG.tar.gz
|
f59adf36a0fcf4c94198e7d3d776c1b3824211ab7aeebeb31fe19836661196aa $SDL.tar.gz
|
||||||
|
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
|
||||||
|
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||||
|
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
|
||||||
|
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
|
||||||
|
04705c110cb2469caa79fb71fba3d7bf834914706e9641a4589485c1f832565b jpegsrc.v$LIBJPEG.tar.gz
|
||||||
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
|
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
|
||||||
5087c9e5b0165e7bc3c1a4ab176b35d0cd8f52636aea903fa377bdba00891a60 qtbase-everywhere-src-$QT.tar.xz
|
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
|
||||||
0aff58062e74b84617c5da8325d8cdad5368d8f4d2a11ceafcd58329fe99b798 qtimageformats-everywhere-src-$QT.tar.xz
|
c5f22a5e10fb162895ded7de0963328e7307611c688487b5d152c9ee64767599 qtbase-everywhere-src-$QT.tar.xz
|
||||||
88315f886cf81898705e487cedba6e6160724359d23c518c92c333c098879a4a qtsvg-everywhere-src-$QT.tar.xz
|
e1a1d8785fae67d16ad0a443b01d5f32663a6b68d275f1806ebab257485ce5d6 qtimageformats-everywhere-src-$QT.tar.xz
|
||||||
867df829cd5cd3ae8efe62e825503123542764b13c96953511e567df70c5a091 qttools-everywhere-src-$QT.tar.xz
|
fb0d1286a35be3583fee34aeb5843c94719e07193bdf1d4d8b0dc14009caef01 qtsvg-everywhere-src-$QT.tar.xz
|
||||||
79e56b7800d49649a8a8010818538c367a829e0b7a09d5f60bd3aecf5abe972c qttranslations-everywhere-src-$QT.tar.xz
|
58e855ad1b2533094726c8a425766b63a04a0eede2ed85086860e54593aa4b2a qttools-everywhere-src-$QT.tar.xz
|
||||||
|
9845780b5dc1b7279d57836db51aeaf2e4a1160c42be09750616f39157582ca9 qttranslations-everywhere-src-$QT.tar.xz
|
||||||
|
eb3b5f0c16313d34f208d90c2fa1e588a23283eed63b101edd5422be6165d528 shaderc-$SHADERC.tar.gz
|
||||||
|
aa27e4454ce631c5a17924ce0624eac736da19fc6f5a2ab15a6c58da7b36950f shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||||
|
5d866ce34a4b6908e262e5ebfffc0a5e11dd411640b5f24c85a80ad44c0d4697 shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||||
|
03ee1a2c06f3b61008478f4abe9423454e53e580b9488b47c8071547c6a9db47 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
curl -L \
|
curl -L \
|
||||||
|
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
|
||||||
|
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
|
||||||
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
||||||
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$PNG/libpng-$PNG.tar.xz" \
|
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||||
-O "https://www.ijg.org/files/jpegsrc.v$JPG.tar.gz" \
|
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||||
|
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
|
||||||
|
-O "https://ijg.org/files/jpegsrc.v$LIBJPEG.tar.gz" \
|
||||||
|
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||||
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
||||||
|
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
|
||||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
|
||||||
|
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
|
||||||
|
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
|
||||||
|
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
|
||||||
|
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz"
|
||||||
|
|
||||||
shasum -a 256 --check SHASUMS
|
shasum -a 256 --check SHASUMS
|
||||||
|
|
||||||
echo "Installing SDL..."
|
echo "Installing SDL..."
|
||||||
|
rm -fr "$SDL"
|
||||||
tar xf "$SDL.tar.gz"
|
tar xf "$SDL.tar.gz"
|
||||||
cd "$SDL"
|
cd "$SDL"
|
||||||
|
cmake -B build "${CMAKE_COMMON[@]}" -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON
|
||||||
# MFI causes multiple joystick connection events, I'm guessing because both the HIDAPI and MFI interfaces
|
|
||||||
# race each other, and sometimes both end up getting through. So, just force MFI off.
|
|
||||||
patch -u CMakeLists.txt <<EOF
|
|
||||||
--- CMakeLists.txt 2023-08-03 01:33:11
|
|
||||||
+++ CMakeLists.txt 2023-08-26 12:58:53
|
|
||||||
@@ -2105,7 +2105,7 @@
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <CoreHaptics/CoreHaptics.h>
|
|
||||||
int main() { return 0; }" HAVE_FRAMEWORK_COREHAPTICS)
|
|
||||||
- if(HAVE_FRAMEWORK_GAMECONTROLLER AND HAVE_FRAMEWORK_COREHAPTICS)
|
|
||||||
+ if(HAVE_FRAMEWORK_GAMECONTROLLER AND HAVE_FRAMEWORK_COREHAPTICS AND FALSE)
|
|
||||||
# Only enable MFI if we also have CoreHaptics to ensure rumble works
|
|
||||||
set(SDL_JOYSTICK_MFI 1)
|
|
||||||
set(SDL_FRAMEWORK_GAMECONTROLLER 1)
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DSDL_X11=OFF
|
|
||||||
make -C build "-j$NPROCS"
|
make -C build "-j$NPROCS"
|
||||||
make -C build install
|
make -C build install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
|
if [ "$BUILD_FFMPEG" -ne 0 ]; then
|
||||||
|
echo "Installing FFmpeg..."
|
||||||
|
rm -fr "ffmpeg-$FFMPEG"
|
||||||
|
tar xf "ffmpeg-$FFMPEG.tar.xz"
|
||||||
|
cd "ffmpeg-$FFMPEG"
|
||||||
|
LDFLAGS="-dead_strip $LDFLAGS" CFLAGS="-Os $CFLAGS" CXXFLAGS="-Os $CXXFLAGS" \
|
||||||
|
./configure --prefix="$INSTALLDIR" \
|
||||||
|
--enable-cross-compile --arch=x86_64 --cc='clang -arch x86_64' --cxx='clang++ -arch x86_64' \
|
||||||
|
--disable-all --disable-autodetect --disable-static --enable-shared \
|
||||||
|
--enable-avcodec --enable-avformat --enable-avutil --enable-swresample --enable-swscale \
|
||||||
|
--enable-audiotoolbox --enable-videotoolbox \
|
||||||
|
--enable-encoder=ffv1,qtrle,pcm_s16be,pcm_s16le,*_at,*_videotoolbox \
|
||||||
|
--enable-muxer=avi,matroska,mov,mp3,mp4,wav \
|
||||||
|
--enable-protocol=file
|
||||||
|
make "-j$NPROCS"
|
||||||
|
make install
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing Zstd..."
|
||||||
|
rm -fr "zstd-$ZSTD"
|
||||||
|
tar xf "zstd-$ZSTD.tar.gz"
|
||||||
|
cd "zstd-$ZSTD"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_PROGRAMS=OFF -B build-dir build/cmake
|
||||||
|
make -C build-dir "-j$NPROCS"
|
||||||
|
make -C build-dir install
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Installing LZ4..."
|
||||||
|
rm -fr "lz4-$LZ4"
|
||||||
|
tar xf "$LZ4.tar.gz"
|
||||||
|
cd "lz4-$LZ4"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -B build-dir build/cmake
|
||||||
|
make -C build-dir "-j$NPROCS"
|
||||||
|
make -C build-dir install
|
||||||
|
cd ..
|
||||||
|
|
||||||
echo "Installing libpng..."
|
echo "Installing libpng..."
|
||||||
tar xf "libpng-$PNG.tar.xz"
|
rm -fr "libpng-$LIBPNG"
|
||||||
cd "libpng-$PNG"
|
tar xf "libpng-$LIBPNG.tar.xz"
|
||||||
./configure --prefix "$INSTALLDIR" --disable-dependency-tracking
|
cd "libpng-$LIBPNG"
|
||||||
make "-j$NPROCS"
|
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -DPNG_FRAMEWORK=OFF -B build
|
||||||
make install
|
make -C build "-j$NPROCS"
|
||||||
|
make -C build install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
echo "Installing libjpeg..."
|
echo "Installing libjpeg..."
|
||||||
tar xf "jpegsrc.v$JPG.tar.gz"
|
rm -fr "jpeg-$LIBJPEG"
|
||||||
cd "jpeg-$JPG"
|
tar xf "jpegsrc.v$LIBJPEG.tar.gz"
|
||||||
./configure --prefix "$INSTALLDIR" --disable-dependency-tracking
|
cd "jpeg-$LIBJPEG"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
../configure --prefix="$INSTALLDIR" --disable-static --enable-shared --host="x86_64-apple-darwin" CFLAGS="-arch x86_64"
|
||||||
make "-j$NPROCS"
|
make "-j$NPROCS"
|
||||||
make install
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo "Installing WebP..."
|
||||||
|
rm -fr "libwebp-$LIBWEBP"
|
||||||
|
tar xf "libwebp-$LIBWEBP.tar.gz"
|
||||||
|
cd "libwebp-$LIBWEBP"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" -B build \
|
||||||
|
-DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF \
|
||||||
|
-DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON
|
||||||
|
make -C build "-j$NPROCS"
|
||||||
|
make -C build install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
echo "Installing FFmpeg..."
|
echo "Building FreeType without HarfBuzz..."
|
||||||
tar xf "ffmpeg-$FFMPEG.tar.xz"
|
rm -fr "freetype-$FREETYPE"
|
||||||
cd "ffmpeg-$FFMPEG"
|
tar xf "freetype-$FREETYPE.tar.xz"
|
||||||
./configure --prefix="$INSTALLDIR" --disable-all --disable-autodetect --disable-static --enable-shared \
|
cd "freetype-$FREETYPE"
|
||||||
--enable-avcodec --enable-avformat --enable-avutil --enable-swresample --enable-swscale \
|
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B build
|
||||||
--enable-audiotoolbox --enable-videotoolbox \
|
cmake --build build --parallel
|
||||||
--enable-encoder=ffv1,qtrle,pcm_s16be,pcm_s16le,*_at,*_videotoolbox \
|
cmake --install build
|
||||||
--enable-muxer=avi,matroska,mov,mp3,mp4,wav \
|
cd ..
|
||||||
--enable-protocol=file
|
|
||||||
make "-j$NPROCS"
|
echo "Building HarfBuzz..."
|
||||||
make install
|
rm -fr "harfbuzz-$HARFBUZZ"
|
||||||
|
tar xf "harfbuzz-$HARFBUZZ.tar.gz"
|
||||||
|
cd "harfbuzz-$HARFBUZZ"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -B build
|
||||||
|
cmake --build build --parallel
|
||||||
|
cmake --install build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Building FreeType with HarfBuzz..."
|
||||||
|
rm -fr "freetype-$FREETYPE"
|
||||||
|
tar xf "freetype-$FREETYPE.tar.xz"
|
||||||
|
cd "freetype-$FREETYPE"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_REQUIRE_HARFBUZZ=TRUE -B build
|
||||||
|
cmake --build build --parallel
|
||||||
|
cmake --install build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# MoltenVK already builds universal binaries, nothing special to do here.
|
||||||
|
echo "Installing MoltenVK..."
|
||||||
|
rm -fr "MoltenVK-${MOLTENVK}"
|
||||||
|
tar xf "v$MOLTENVK.tar.gz"
|
||||||
|
cd "MoltenVK-${MOLTENVK}"
|
||||||
|
sed -i '' 's/xcodebuild "$@"/xcodebuild $XCODEBUILD_EXTRA_ARGS "$@"/g' fetchDependencies
|
||||||
|
sed -i '' 's/XCODEBUILD :=/XCODEBUILD ?=/g' Makefile
|
||||||
|
XCODEBUILD_EXTRA_ARGS="VALID_ARCHS=x86_64" ./fetchDependencies --macos
|
||||||
|
XCODEBUILD="set -o pipefail && xcodebuild VALID_ARCHS=x86_64" make macos
|
||||||
|
cp Package/Latest/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib "$INSTALLDIR/lib/"
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
echo "Installing Qt Base..."
|
echo "Installing Qt Base..."
|
||||||
|
rm -fr "qtbase-everywhere-src-$QT"
|
||||||
tar xf "qtbase-everywhere-src-$QT.tar.xz"
|
tar xf "qtbase-everywhere-src-$QT.tar.xz"
|
||||||
cd "qtbase-everywhere-src-$QT"
|
cd "qtbase-everywhere-src-$QT"
|
||||||
# Qt's panel:shouldEnableURL: implementation does a whole bunch of things that activate macOS's sandbox permissions dialog
|
|
||||||
# Since this is called on every file being displayed in the open/save panel, that spams users with permissions dialogs
|
|
||||||
# Simple solution: Hopefully no one needs any filters that aren't simple file extension filters, remove all other handling
|
|
||||||
patch -u src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm <<EOF
|
|
||||||
--- src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
|
|
||||||
+++ src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
|
|
||||||
@@ -133,7 +133,5 @@
|
|
||||||
NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
|
|
||||||
- bool selectable = (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
|
|
||||||
- || [self panel:m_panel shouldEnableURL:url];
|
|
||||||
|
|
||||||
m_panel.directoryURL = [NSURL fileURLWithPath:m_currentDirectory];
|
# since we don't have a direct reference to QtSvg, it doesn't deployed directly from the main binary
|
||||||
- m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
|
# (only indirectly from iconengines), and the libqsvg.dylib imageformat plugin does not get deployed.
|
||||||
+ m_panel.nameFieldStringValue = info.fileName().toNSString();
|
# We could run macdeployqt twice, but that's even more janky than patching it.
|
||||||
|
|
||||||
@@ -203,61 +201,2 @@
|
# https://github.com/qt/qtbase/commit/7b018629c3c3ab23665bf1da00c43c1546042035
|
||||||
return hidden;
|
# The QProcess default wait time of 30s may be too short in e.g. CI environments where processes may be blocked
|
||||||
-}
|
# for a longer time waiting for CPU or IO.
|
||||||
|
|
||||||
|
patch -u src/tools/macdeployqt/shared/shared.cpp <<EOF
|
||||||
|
--- shared.cpp
|
||||||
|
+++ shared.cpp
|
||||||
|
@@ -152,7 +152,7 @@
|
||||||
|
LogDebug() << " inspecting" << binaryPath;
|
||||||
|
QProcess otool;
|
||||||
|
otool.start("otool", QStringList() << "-L" << binaryPath);
|
||||||
|
- otool.waitForFinished();
|
||||||
|
+ otool.waitForFinished(-1);
|
||||||
|
|
||||||
|
if (otool.exitStatus() != QProcess::NormalExit || otool.exitCode() != 0) {
|
||||||
|
LogError() << otool.readAllStandardError();
|
||||||
|
@@ -1122,14 +1122,8 @@
|
||||||
|
addPlugins(QStringLiteral("networkinformation"));
|
||||||
|
}
|
||||||
|
|
||||||
|
- // All image formats (svg if QtSvg is used)
|
||||||
|
- const bool usesSvg = deploymentInfo.containsModule("Svg", libInfix);
|
||||||
|
- addPlugins(QStringLiteral("imageformats"), [usesSvg](const QString &lib) {
|
||||||
|
- if (lib.contains(QStringLiteral("qsvg")) && !usesSvg)
|
||||||
|
- return false;
|
||||||
|
- return true;
|
||||||
|
- });
|
||||||
-
|
-
|
||||||
-- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url
|
+ // All image formats
|
||||||
-{
|
+ addPlugins(QStringLiteral("imageformats"));
|
||||||
- Q_UNUSED(sender);
|
addPlugins(QStringLiteral("iconengines"));
|
||||||
-
|
|
||||||
- NSString *filename = url.path;
|
// Platforminputcontext plugins if QtGui is in use
|
||||||
- if (!filename.length)
|
|
||||||
- return NO;
|
|
||||||
-
|
|
||||||
- // Always accept directories regardless of their names (unless it is a bundle):
|
|
||||||
- NSFileManager *fm = NSFileManager.defaultManager;
|
|
||||||
- NSDictionary *fileAttrs = [fm attributesOfItemAtPath:filename error:nil];
|
|
||||||
- if (!fileAttrs)
|
|
||||||
- return NO; // Error accessing the file means 'no'.
|
|
||||||
- NSString *fileType = fileAttrs.fileType;
|
|
||||||
- bool isDir = [fileType isEqualToString:NSFileTypeDirectory];
|
|
||||||
- if (isDir) {
|
|
||||||
- if (!m_panel.treatsFilePackagesAsDirectories) {
|
|
||||||
- if ([NSWorkspace.sharedWorkspace isFilePackageAtPath:filename] == NO)
|
|
||||||
- return YES;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- // Treat symbolic links and aliases to directories like directories
|
|
||||||
- QFileInfo fileInfo(QString::fromNSString(filename));
|
|
||||||
- if (fileInfo.isSymLink() && QFileInfo(fileInfo.symLinkTarget()).isDir())
|
|
||||||
- return YES;
|
|
||||||
-
|
|
||||||
- QString qtFileName = fileInfo.fileName();
|
|
||||||
- // No filter means accept everything
|
|
||||||
- bool nameMatches = m_selectedNameFilter->isEmpty();
|
|
||||||
- // Check if the current file name filter accepts the file:
|
|
||||||
- for (int i = 0; !nameMatches && i < m_selectedNameFilter->size(); ++i) {
|
|
||||||
- if (QDir::match(m_selectedNameFilter->at(i), qtFileName))
|
|
||||||
- nameMatches = true;
|
|
||||||
- }
|
|
||||||
- if (!nameMatches)
|
|
||||||
- return NO;
|
|
||||||
-
|
|
||||||
- QDir::Filters filter = m_options->filter();
|
|
||||||
- if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && isDir)
|
|
||||||
- || (!(filter & QDir::Files) && [fileType isEqualToString:NSFileTypeRegular])
|
|
||||||
- || ((filter & QDir::NoSymLinks) && [fileType isEqualToString:NSFileTypeSymbolicLink]))
|
|
||||||
- return NO;
|
|
||||||
-
|
|
||||||
- bool filterPermissions = ((filter & QDir::PermissionMask)
|
|
||||||
- && (filter & QDir::PermissionMask) != QDir::PermissionMask);
|
|
||||||
- if (filterPermissions) {
|
|
||||||
- if ((!(filter & QDir::Readable) && [fm isReadableFileAtPath:filename])
|
|
||||||
- || (!(filter & QDir::Writable) && [fm isWritableFileAtPath:filename])
|
|
||||||
- || (!(filter & QDir::Executable) && [fm isExecutableFileAtPath:filename]))
|
|
||||||
- return NO;
|
|
||||||
- }
|
|
||||||
- if (!(filter & QDir::Hidden)
|
|
||||||
- && (qtFileName.startsWith(u'.') || [self isHiddenFileAtURL:url]))
|
|
||||||
- return NO;
|
|
||||||
-
|
|
||||||
- return YES;
|
|
||||||
}
|
|
||||||
@@ -406,5 +345,2 @@
|
|
||||||
{
|
|
||||||
- if (m_options->acceptMode() != QFileDialogOptions::AcceptSave)
|
|
||||||
- return nil; // panel:shouldEnableURL: does the file filtering for NSOpenPanel
|
|
||||||
-
|
|
||||||
QStringList fileTypes;
|
|
||||||
EOF
|
EOF
|
||||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release -DFEATURE_optimize_size=ON -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF
|
cmake -B build "${CMAKE_COMMON[@]}" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
|
||||||
make -C build "-j$NPROCS"
|
make -C build "-j$NPROCS"
|
||||||
make -C build install
|
make -C build install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
echo "Installing Qt SVG..."
|
echo "Installing Qt SVG..."
|
||||||
|
rm -fr "qtsvg-everywhere-src-$QT"
|
||||||
tar xf "qtsvg-everywhere-src-$QT.tar.xz"
|
tar xf "qtsvg-everywhere-src-$QT.tar.xz"
|
||||||
cd "qtsvg-everywhere-src-$QT"
|
cd "qtsvg-everywhere-src-$QT"
|
||||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=MinSizeRel
|
mkdir build
|
||||||
make -C build "-j$NPROCS"
|
cd build
|
||||||
make -C build install
|
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}"
|
||||||
cd ..
|
make "-j$NPROCS"
|
||||||
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
echo "Installing Qt Image Formats..."
|
echo "Installing Qt Image Formats..."
|
||||||
|
rm -fr "qtimageformats-everywhere-src-$QT"
|
||||||
tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
|
tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
|
||||||
cd "qtimageformats-everywhere-src-$QT"
|
cd "qtimageformats-everywhere-src-$QT"
|
||||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=MinSizeRel
|
mkdir build
|
||||||
make -C build "-j$NPROCS"
|
cd build
|
||||||
make -C build install
|
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" -DFEATURE_system_webp=ON
|
||||||
cd ..
|
make "-j$NPROCS"
|
||||||
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
echo "Installing Qt Tools..."
|
echo "Installing Qt Tools..."
|
||||||
|
rm -fr "qttools-everywhere-src-$QT"
|
||||||
tar xf "qttools-everywhere-src-$QT.tar.xz"
|
tar xf "qttools-everywhere-src-$QT.tar.xz"
|
||||||
cd "qttools-everywhere-src-$QT"
|
cd "qttools-everywhere-src-$QT"
|
||||||
# Linguist relies on a library in the Designer target, which takes 5-7 minutes to build on the CI
|
mkdir build
|
||||||
# Avoid it by not building Linguist, since we only need the tools that come with it
|
cd build
|
||||||
patch -u src/linguist/CMakeLists.txt <<EOF
|
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
|
||||||
--- src/linguist/CMakeLists.txt
|
make "-j$NPROCS"
|
||||||
+++ src/linguist/CMakeLists.txt
|
make install
|
||||||
@@ -14,7 +14,7 @@
|
cd ../..
|
||||||
add_subdirectory(lrelease-pro)
|
|
||||||
add_subdirectory(lupdate)
|
echo "Building shaderc..."
|
||||||
add_subdirectory(lupdate-pro)
|
rm -fr "shaderc-$SHADERC"
|
||||||
-if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png)
|
tar xf "shaderc-$SHADERC.tar.gz"
|
||||||
+if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND TARGET Qt::PrintSupport AND NOT no-png)
|
cd "shaderc-$SHADERC"
|
||||||
add_subdirectory(linguist)
|
cd third_party
|
||||||
endif()
|
tar xf "../../shaderc-glslang-$SHADERC_GLSLANG.tar.gz"
|
||||||
EOF
|
mv "glslang-$SHADERC_GLSLANG" "glslang"
|
||||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
|
tar xf "../../shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz"
|
||||||
|
mv "SPIRV-Headers-$SHADERC_SPIRVHEADERS" "spirv-headers"
|
||||||
|
tar xf "../../shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz"
|
||||||
|
mv "SPIRV-Tools-$SHADERC_SPIRVTOOLS" "spirv-tools"
|
||||||
|
cd ..
|
||||||
|
patch -p1 < "$SCRIPTDIR/../common/shaderc-changes.patch"
|
||||||
|
cmake "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSHADERC_SKIP_TESTS=ON -DSHADERC_SKIP_EXAMPLES=ON -DSHADERC_SKIP_COPYRIGHT_CHECK=ON -B build
|
||||||
make -C build "-j$NPROCS"
|
make -C build "-j$NPROCS"
|
||||||
make -C build install
|
make -C build install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
echo "Installing Qt Translations..."
|
echo "Installing Qt Translations..."
|
||||||
|
rm -fr "qttranslations-everywhere-src-$QT"
|
||||||
tar xf "qttranslations-everywhere-src-$QT.tar.xz"
|
tar xf "qttranslations-everywhere-src-$QT.tar.xz"
|
||||||
cd "qttranslations-everywhere-src-$QT"
|
cd "qttranslations-everywhere-src-$QT"
|
||||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release
|
mkdir build
|
||||||
make -C build "-j$NPROCS"
|
cd build
|
||||||
make -C build install
|
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}"
|
||||||
cd ..
|
make "-j$NPROCS"
|
||||||
|
make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
echo "Cleaning up..."
|
echo "Cleaning up..."
|
||||||
cd ..
|
cd ..
|
||||||
rm -r deps-build
|
rm -rf deps-build
|
||||||
|
|
|
@ -461,15 +461,15 @@
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.2.3",
|
"version": "8.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"bufferutil": "^4.0.1",
|
"bufferutil": "^4.0.1",
|
||||||
"utf-8-validate": "^5.0.2"
|
"utf-8-validate": ">=5.0.2"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"bufferutil": {
|
"bufferutil": {
|
||||||
|
@ -842,9 +842,9 @@
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "8.2.3",
|
"version": "8.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,296 @@
|
||||||
|
@echo off
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
echo Setting environment...
|
||||||
|
if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" (
|
||||||
|
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsamd64_arm64.bat"
|
||||||
|
) else if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" (
|
||||||
|
call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsamd64_arm64.bat"
|
||||||
|
) else (
|
||||||
|
echo Visual Studio 2022 not found.
|
||||||
|
goto error
|
||||||
|
)
|
||||||
|
|
||||||
|
set SEVENZIP="C:\Program Files\7-Zip\7z.exe"
|
||||||
|
set PATCH="C:\Program Files\Git\usr\bin\patch.exe"
|
||||||
|
|
||||||
|
if defined DEBUG (
|
||||||
|
echo DEBUG=%DEBUG%
|
||||||
|
) else (
|
||||||
|
set DEBUG=1
|
||||||
|
)
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
set "SCRIPTDIR=%CD%"
|
||||||
|
cd ..\..\..\..
|
||||||
|
mkdir deps-build
|
||||||
|
cd deps-build || goto error
|
||||||
|
set "BUILDDIR=%CD%"
|
||||||
|
cd ..
|
||||||
|
mkdir deps-arm64
|
||||||
|
cd deps-arm64 || goto error
|
||||||
|
set "INSTALLDIR=%CD%"
|
||||||
|
cd ..
|
||||||
|
cd deps || goto error
|
||||||
|
set "X64INSTALLDIR=%CD%"
|
||||||
|
cd ..
|
||||||
|
popd
|
||||||
|
|
||||||
|
echo SCRIPTDIR=%SCRIPTDIR%
|
||||||
|
echo BUILDDIR=%BUILDDIR%
|
||||||
|
echo INSTALLDIR=%INSTALLDIR%
|
||||||
|
|
||||||
|
cd "%BUILDDIR%"
|
||||||
|
|
||||||
|
set FREETYPE=2.13.3
|
||||||
|
set HARFBUZZ=10.0.1
|
||||||
|
set LIBJPEG=9f
|
||||||
|
set LIBPNG=1643
|
||||||
|
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||||
|
set QT=6.8.1
|
||||||
|
set QTMINOR=6.8
|
||||||
|
set SDL=SDL2-2.30.10
|
||||||
|
set WEBP=1.4.0
|
||||||
|
set ZLIB=1.3.1
|
||||||
|
set ZLIBSHORT=131
|
||||||
|
set ZSTD=1.5.6
|
||||||
|
|
||||||
|
set SHADERC=2024.1
|
||||||
|
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||||
|
set SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
|
||||||
|
set SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||||
|
|
||||||
|
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
|
||||||
|
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
|
||||||
|
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1643.zip fc466a1e638e635d6c66363bdf3f38555b81b0141d0b06ba45b49ccca327436d || goto error
|
||||||
|
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
|
||||||
|
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
|
||||||
|
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
|
||||||
|
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 14b06b30d3400953875e73b0c4771cad1483488a1ef816803610f22b32300ce8 || goto error
|
||||||
|
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
|
||||||
|
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
|
||||||
|
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
|
||||||
|
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
|
||||||
|
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
|
||||||
|
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
|
||||||
|
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
|
||||||
|
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
|
||||||
|
|
||||||
|
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
|
||||||
|
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
|
||||||
|
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" fa59a54334feaba5702b9c25724c3f4746123865769b36dd5a28d9ef5e9d39ab || goto error
|
||||||
|
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" bf385994c20293485b378c27dfdbd77a31b949deabccd9218a977f173eda9f6f || goto error
|
||||||
|
|
||||||
|
if %DEBUG%==1 (
|
||||||
|
echo Building debug and release libraries...
|
||||||
|
) else (
|
||||||
|
echo Building release libraries...
|
||||||
|
)
|
||||||
|
|
||||||
|
set FORCEPDB=-DCMAKE_SHARED_LINKER_FLAGS_RELEASE="/DEBUG"
|
||||||
|
set ARM64TOOLCHAIN=-DCMAKE_TOOLCHAIN_FILE="%SCRIPTDIR%\cmake-toolchain-windows-arm64.cmake"
|
||||||
|
|
||||||
|
echo Building Zlib...
|
||||||
|
rmdir /S /Q "zlib-%ZLIB%"
|
||||||
|
%SEVENZIP% x "zlib%ZLIBSHORT%.zip" || goto error
|
||||||
|
cd "zlib-%ZLIB%" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZLIB_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building libpng...
|
||||||
|
rmdir /S /Q "lpng%LIBPNG%"
|
||||||
|
%SEVENZIP% x "lpng%LIBPNG%.zip" || goto error
|
||||||
|
cd "lpng%LIBPNG%" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -DPNG_STATIC=OFF -DPNG_SHARED=ON -DPNG_TOOLS=OFF -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building libjpeg...
|
||||||
|
rmdir /S /Q "jpeg-%LIBJPEG%"
|
||||||
|
%SEVENZIP% x "jpegsr%LIBJPEG%.zip" || goto error
|
||||||
|
cd "jpeg-%LIBJPEG%" || goto error
|
||||||
|
%PATCH% -p1 < "%SCRIPTDIR%\libjpeg-cmake.patch" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=OFF -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building LZ4...
|
||||||
|
rmdir /S /Q "lz4"
|
||||||
|
%SEVENZIP% x "lz4-%LZ4%.zip" || goto error
|
||||||
|
rename "lz4-%LZ4%" "lz4" || goto error
|
||||||
|
cd "lz4" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -DCMAKE_C_FLAGS="/wd4711 /wd5045" -B build-dir -G Ninja build/cmake || goto error
|
||||||
|
cmake --build build-dir --parallel || goto error
|
||||||
|
ninja -C build-dir install || goto error
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo Building FreeType without HarfBuzz...
|
||||||
|
rmdir /S /Q "freetype-%FREETYPE%"
|
||||||
|
tar -xf "freetype-%FREETYPE%.tar.gz" || goto error
|
||||||
|
cd "freetype-%FREETYPE%" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=TRUE -DFT_REQUIRE_PNG=TRUE -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building HarfBuzz...
|
||||||
|
rmdir /S /Q "harfbuzz-%HARFBUZZ%"
|
||||||
|
%SEVENZIP% x "-x^!harfbuzz-%HARFBUZZ%\README" "harfbuzz-%HARFBUZZ%.zip" || goto error
|
||||||
|
cd "harfbuzz-%HARFBUZZ%" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building FreeType with HarfBuzz...
|
||||||
|
rmdir /S /Q "freetype-%FREETYPE%"
|
||||||
|
tar -xf "freetype-%FREETYPE%.tar.gz" || goto error
|
||||||
|
cd "freetype-%FREETYPE%" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=TRUE -DFT_REQUIRE_PNG=TRUE -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_REQUIRE_HARFBUZZ=TRUE -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building Zstandard...
|
||||||
|
rmdir /S /Q "zstd-%ZSTD%"
|
||||||
|
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
|
||||||
|
cd "zstd-%ZSTD%"
|
||||||
|
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building WebP...
|
||||||
|
rmdir /S /Q "libwebp-%WEBP%"
|
||||||
|
tar -xf "libwebp-%WEBP%.tar.gz" || goto error
|
||||||
|
cd "libwebp-%WEBP%" || goto error
|
||||||
|
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF -DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building SDL...
|
||||||
|
rmdir /S /Q "%SDL%"
|
||||||
|
%SEVENZIP% x "%SDL%.zip" || goto error
|
||||||
|
cd "%SDL%" || goto error
|
||||||
|
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
if %DEBUG%==1 (
|
||||||
|
set QTBUILDSPEC=-DCMAKE_CONFIGURATION_TYPES="Release;Debug" -G "Ninja Multi-Config"
|
||||||
|
) else (
|
||||||
|
set QTBUILDSPEC=-DCMAKE_BUILD_TYPE=Release -G Ninja
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Building Qt base...
|
||||||
|
rmdir /S /Q "qtbase-everywhere-src-%QT%"
|
||||||
|
%SEVENZIP% x "qtbase-everywhere-src-%QT%.zip" || goto error
|
||||||
|
cd "qtbase-everywhere-src-%QT%" || goto error
|
||||||
|
cmake -B build %ARM64TOOLCHAIN% -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DQT_HOST_PATH="%X64INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building Qt SVG...
|
||||||
|
rmdir /S /Q "qtsvg-everywhere-src-%QT%"
|
||||||
|
%SEVENZIP% x "qtsvg-everywhere-src-%QT%.zip" || goto error
|
||||||
|
cd "qtsvg-everywhere-src-%QT%" || goto error
|
||||||
|
mkdir build || goto error
|
||||||
|
cd build || goto error
|
||||||
|
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- %FORCEPDB% -DCMAKE_PREFIX_PATH="%INSTALLDIR%" || goto error
|
||||||
|
cmake --build . --parallel || goto error
|
||||||
|
ninja install || goto error
|
||||||
|
cd ..\.. || goto error
|
||||||
|
|
||||||
|
echo Building Qt Image Formats...
|
||||||
|
rmdir /S /Q "qtimageformats-everywhere-src-%QT%"
|
||||||
|
%SEVENZIP% x "qtimageformats-everywhere-src-%QT%.zip" || goto error
|
||||||
|
cd "qtimageformats-everywhere-src-%QT%" || goto error
|
||||||
|
mkdir build || goto error
|
||||||
|
cd build || goto error
|
||||||
|
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- %FORCEPDB% -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DFEATURE_system_webp=ON || goto error
|
||||||
|
cmake --build . --parallel || goto error
|
||||||
|
ninja install || goto error
|
||||||
|
cd ..\.. || goto error
|
||||||
|
|
||||||
|
echo Building Qt Tools...
|
||||||
|
rmdir /S /Q "qtimageformats-everywhere-src-%QT%"
|
||||||
|
%SEVENZIP% x "qttools-everywhere-src-%QT%.zip" || goto error
|
||||||
|
cd "qttools-everywhere-src-%QT%" || goto error
|
||||||
|
mkdir build || goto error
|
||||||
|
cd build || goto error
|
||||||
|
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- %FORCEPDB% -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF || goto error
|
||||||
|
cmake --build . --parallel || goto error
|
||||||
|
ninja install || goto error
|
||||||
|
cd ..\.. || goto error
|
||||||
|
|
||||||
|
echo Building Qt Translations...
|
||||||
|
rmdir /S /Q "qttranslations-everywhere-src-%QT%"
|
||||||
|
%SEVENZIP% x "qttranslations-everywhere-src-%QT%.zip" || goto error
|
||||||
|
cd "qttranslations-everywhere-src-%QT%" || goto error
|
||||||
|
mkdir build || goto error
|
||||||
|
cd build || goto error
|
||||||
|
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- %FORCEPDB% || goto error
|
||||||
|
cmake --build . --parallel || goto error
|
||||||
|
ninja install || goto error
|
||||||
|
cd ..\.. || goto error
|
||||||
|
|
||||||
|
echo Building shaderc...
|
||||||
|
rmdir /S /Q "shaderc-%SHADERC%"
|
||||||
|
%SEVENZIP% x "shaderc-%SHADERC%.zip" || goto error
|
||||||
|
cd "shaderc-%SHADERC%" || goto error
|
||||||
|
cd third_party || goto error
|
||||||
|
%SEVENZIP% x "..\..\shaderc-glslang-%SHADERC_GLSLANG%.zip" || goto error
|
||||||
|
rename "glslang-%SHADERC_GLSLANG%" "glslang" || goto error
|
||||||
|
%SEVENZIP% x "..\..\shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" || goto error
|
||||||
|
rename "SPIRV-Headers-%SHADERC_SPIRVHEADERS%" "spirv-headers" || goto error
|
||||||
|
%SEVENZIP% x "..\..\shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" || goto error
|
||||||
|
rename "SPIRV-Tools-%SHADERC_SPIRVTOOLS%" "spirv-tools" || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
%PATCH% -p1 < "%SCRIPTDIR%\..\common\shaderc-changes.patch" || goto error
|
||||||
|
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DSHADERC_SKIP_TESTS=ON -DSHADERC_SKIP_EXAMPLES=ON -DSHADERC_SKIP_COPYRIGHT_CHECK=ON -DSHADERC_ENABLE_SHARED_CRT=ON -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Cleaning up...
|
||||||
|
cd ..
|
||||||
|
rd /S /Q deps-build
|
||||||
|
|
||||||
|
echo Exiting with success.
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
:error
|
||||||
|
echo Failed with error #%errorlevel%.
|
||||||
|
pause
|
||||||
|
exit %errorlevel%
|
||||||
|
|
||||||
|
:downloadfile
|
||||||
|
if not exist "%~1" (
|
||||||
|
echo Downloading %~1 from %~2...
|
||||||
|
curl -L -o "%~1" "%~2" || goto error
|
||||||
|
)
|
||||||
|
|
||||||
|
rem based on https://gist.github.com/gsscoder/e22daefaff9b5d8ac16afb070f1a7971
|
||||||
|
set idx=0
|
||||||
|
for /f %%F in ('certutil -hashfile "%~1" SHA256') do (
|
||||||
|
set "out!idx!=%%F"
|
||||||
|
set /a idx += 1
|
||||||
|
)
|
||||||
|
set filechecksum=%out1%
|
||||||
|
|
||||||
|
if /i %~3==%filechecksum% (
|
||||||
|
echo Validated %~1.
|
||||||
|
exit /B 0
|
||||||
|
) else (
|
||||||
|
echo Expected %~3 got %filechecksum%.
|
||||||
|
exit /B 1
|
||||||
|
)
|
|
@ -12,6 +12,7 @@ if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Bu
|
||||||
)
|
)
|
||||||
|
|
||||||
set SEVENZIP="C:\Program Files\7-Zip\7z.exe"
|
set SEVENZIP="C:\Program Files\7-Zip\7z.exe"
|
||||||
|
set PATCH="C:\Program Files\Git\usr\bin\patch.exe"
|
||||||
|
|
||||||
if defined DEBUG (
|
if defined DEBUG (
|
||||||
echo DEBUG=%DEBUG%
|
echo DEBUG=%DEBUG%
|
||||||
|
@ -35,20 +36,48 @@ echo SCRIPTDIR=%SCRIPTDIR%
|
||||||
echo BUILDDIR=%BUILDDIR%
|
echo BUILDDIR=%BUILDDIR%
|
||||||
echo INSTALLDIR=%INSTALLDIR%
|
echo INSTALLDIR=%INSTALLDIR%
|
||||||
|
|
||||||
|
set "PATH=%PATH%;%INSTALLDIR%\bin"
|
||||||
|
|
||||||
cd "%BUILDDIR%"
|
cd "%BUILDDIR%"
|
||||||
|
|
||||||
set QT=6.5.2
|
set FREETYPE=2.13.3
|
||||||
set QTMINOR=6.5
|
set HARFBUZZ=10.0.1
|
||||||
set SDL=SDL2-2.28.2
|
set LIBJPEG=9f
|
||||||
|
set LIBPNG=1643
|
||||||
|
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||||
|
set QT=6.8.1
|
||||||
|
set QTMINOR=6.8
|
||||||
|
set SDL=SDL2-2.30.10
|
||||||
|
set WEBP=1.4.0
|
||||||
|
set ZLIB=1.3.1
|
||||||
|
set ZLIBSHORT=131
|
||||||
|
set ZSTD=1.5.6
|
||||||
|
|
||||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 22383a6b242bac072f949d2b3854cf04c6856cae7a87eaa78c60dd733b71e41e || goto error
|
set SHADERC=2024.1
|
||||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" f770a087e350d688441880d08ad2791465e5e3b9a0f8fc2cfbeb5dd305a11d50 || goto error
|
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
|
||||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 9757899b00eea4e6b65f81f922c0215c70969661567398d91da6639a50a788e7 || goto error
|
set SHADERC_SPIRVHEADERS=5e3ad389ee56fca27c9705d093ae5387ce404df4
|
||||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 0546a6aa19f5e0188d1ba4a0e0a1423d22b7dc55ce8a614cc4aa65bfac506f74 || goto error
|
set SHADERC_SPIRVTOOLS=dd4b663e13c07fea4fbb3f70c1c91c86731099f7
|
||||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3148f4f263bf9930d89107eb44bc452481a5f8c6178459e26ecbf3c8dca3b5c7 || goto error
|
|
||||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 8b99046b54c40106d4e310be63b41331b717cfd8b42da4b4fc1c9169604be7fc || goto error
|
|
||||||
|
|
||||||
call :downloadfile "4b119f48f5cb5e1499f91a0791150231c47430d4.diff" "https://github.com/qt/qtbase/commit/4b119f48f5cb5e1499f91a0791150231c47430d4.diff" d86bd2bd4ee2aff5f5e97da027aa926178dca250d163427eb21503bb357730a5 || goto error
|
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
|
||||||
|
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
|
||||||
|
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1643.zip fc466a1e638e635d6c66363bdf3f38555b81b0141d0b06ba45b49ccca327436d || goto error
|
||||||
|
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
|
||||||
|
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
|
||||||
|
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
|
||||||
|
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 14b06b30d3400953875e73b0c4771cad1483488a1ef816803610f22b32300ce8 || goto error
|
||||||
|
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
|
||||||
|
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
|
||||||
|
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
|
||||||
|
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
|
||||||
|
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
|
||||||
|
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
|
||||||
|
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
|
||||||
|
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
|
||||||
|
|
||||||
|
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
|
||||||
|
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
|
||||||
|
call :downloadfile "shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" "https://github.com/KhronosGroup/SPIRV-Headers/archive/%SHADERC_SPIRVHEADERS%.zip" fa59a54334feaba5702b9c25724c3f4746123865769b36dd5a28d9ef5e9d39ab || goto error
|
||||||
|
call :downloadfile "shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" "https://github.com/KhronosGroup/SPIRV-Tools/archive/%SHADERC_SPIRVTOOLS%.zip" bf385994c20293485b378c27dfdbd77a31b949deabccd9218a977f173eda9f6f || goto error
|
||||||
|
|
||||||
if %DEBUG%==1 (
|
if %DEBUG%==1 (
|
||||||
echo Building debug and release libraries...
|
echo Building debug and release libraries...
|
||||||
|
@ -56,18 +85,100 @@ if %DEBUG%==1 (
|
||||||
echo Building release libraries...
|
echo Building release libraries...
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set FORCEPDB=-DCMAKE_SHARED_LINKER_FLAGS_RELEASE="/DEBUG"
|
||||||
|
|
||||||
|
echo Building Zlib...
|
||||||
|
rmdir /S /Q "zlib-%ZLIB%"
|
||||||
|
%SEVENZIP% x "zlib%ZLIBSHORT%.zip" || goto error
|
||||||
|
cd "zlib-%ZLIB%" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZLIB_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building libpng...
|
||||||
|
rmdir /S /Q "lpng%LIBPNG%"
|
||||||
|
%SEVENZIP% x "lpng%LIBPNG%.zip" || goto error
|
||||||
|
cd "lpng%LIBPNG%" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -DPNG_STATIC=OFF -DPNG_SHARED=ON -DPNG_TOOLS=OFF -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building libjpeg...
|
||||||
|
rmdir /S /Q "jpeg-%LIBJPEG%"
|
||||||
|
%SEVENZIP% x "jpegsr%LIBJPEG%.zip" || goto error
|
||||||
|
cd "jpeg-%LIBJPEG%" || goto error
|
||||||
|
%PATCH% -p1 < "%SCRIPTDIR%\libjpeg-cmake.patch" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=OFF -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building LZ4...
|
||||||
|
rmdir /S /Q "lz4"
|
||||||
|
%SEVENZIP% x "lz4-%LZ4%.zip" || goto error
|
||||||
|
rename "lz4-%LZ4%" "lz4" || goto error
|
||||||
|
cd "lz4" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -DCMAKE_C_FLAGS="/wd4711 /wd5045" -B build-dir -G Ninja build/cmake || goto error
|
||||||
|
cmake --build build-dir --parallel || goto error
|
||||||
|
ninja -C build-dir install || goto error
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo Building FreeType without HarfBuzz...
|
||||||
|
rmdir /S /Q "freetype-%FREETYPE%"
|
||||||
|
tar -xf "freetype-%FREETYPE%.tar.gz" || goto error
|
||||||
|
cd "freetype-%FREETYPE%" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=TRUE -DFT_REQUIRE_PNG=TRUE -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building HarfBuzz...
|
||||||
|
rmdir /S /Q "harfbuzz-%HARFBUZZ%"
|
||||||
|
%SEVENZIP% x "-x^!harfbuzz-%HARFBUZZ%\README" "harfbuzz-%HARFBUZZ%.zip" || goto error
|
||||||
|
cd "harfbuzz-%HARFBUZZ%" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building FreeType with HarfBuzz...
|
||||||
|
rmdir /S /Q "freetype-%FREETYPE%"
|
||||||
|
tar -xf "freetype-%FREETYPE%.tar.gz" || goto error
|
||||||
|
cd "freetype-%FREETYPE%" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=TRUE -DFT_REQUIRE_PNG=TRUE -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_REQUIRE_HARFBUZZ=TRUE -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building Zstandard...
|
||||||
|
rmdir /S /Q "zstd-%ZSTD%"
|
||||||
|
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
|
||||||
|
cd "zstd-%ZSTD%"
|
||||||
|
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
|
echo Building WebP...
|
||||||
|
rmdir /S /Q "libwebp-%WEBP%"
|
||||||
|
tar -xf "libwebp-%WEBP%.tar.gz" || goto error
|
||||||
|
cd "libwebp-%WEBP%" || goto error
|
||||||
|
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF -DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
echo Building SDL...
|
echo Building SDL...
|
||||||
rmdir /S /Q "%SDL%"
|
rmdir /S /Q "%SDL%"
|
||||||
%SEVENZIP% x "%SDL%.zip" || goto error
|
%SEVENZIP% x "%SDL%.zip" || goto error
|
||||||
cd "%SDL%" || goto error
|
cd "%SDL%" || goto error
|
||||||
if %DEBUG%==1 (
|
cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
|
||||||
cmake -B build-debug -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
|
|
||||||
cmake --build build-debug --parallel || goto error
|
|
||||||
ninja -C build-debug install || goto error
|
|
||||||
)
|
|
||||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
|
|
||||||
cmake --build build --parallel || goto error
|
cmake --build build --parallel || goto error
|
||||||
ninja -C build install || goto error
|
ninja -C build install || goto error
|
||||||
|
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error
|
||||||
cd .. || goto error
|
cd .. || goto error
|
||||||
|
|
||||||
if %DEBUG%==1 (
|
if %DEBUG%==1 (
|
||||||
|
@ -80,8 +191,14 @@ echo Building Qt base...
|
||||||
rmdir /S /Q "qtbase-everywhere-src-%QT%"
|
rmdir /S /Q "qtbase-everywhere-src-%QT%"
|
||||||
%SEVENZIP% x "qtbase-everywhere-src-%QT%.zip" || goto error
|
%SEVENZIP% x "qtbase-everywhere-src-%QT%.zip" || goto error
|
||||||
cd "qtbase-everywhere-src-%QT%" || goto error
|
cd "qtbase-everywhere-src-%QT%" || goto error
|
||||||
"C:\Program Files\Git\usr\bin\patch" -p1 < ../4b119f48f5cb5e1499f91a0791150231c47430d4.diff || goto error
|
|
||||||
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes %QTBUILDSPEC% || goto error
|
rem Disable the PCRE2 JIT, it doesn't properly verify AVX2 support.
|
||||||
|
%PATCH% -p1 < "%SCRIPTDIR%\qtbase-disable-pcre2-jit.patch" || goto error
|
||||||
|
|
||||||
|
rem Hackfix settings icon stretching
|
||||||
|
%PATCH% -p1 < "%SCRIPTDIR%\qtbase-fix-icon-stretch.patch" || goto error
|
||||||
|
|
||||||
|
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
|
||||||
cmake --build build --parallel || goto error
|
cmake --build build --parallel || goto error
|
||||||
ninja -C build install || goto error
|
ninja -C build install || goto error
|
||||||
cd .. || goto error
|
cd .. || goto error
|
||||||
|
@ -92,7 +209,7 @@ rmdir /S /Q "qtsvg-everywhere-src-%QT%"
|
||||||
cd "qtsvg-everywhere-src-%QT%" || goto error
|
cd "qtsvg-everywhere-src-%QT%" || goto error
|
||||||
mkdir build || goto error
|
mkdir build || goto error
|
||||||
cd build || goto error
|
cd build || goto error
|
||||||
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. || goto error
|
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- %FORCEPDB% -DCMAKE_PREFIX_PATH="%INSTALLDIR%" || goto error
|
||||||
cmake --build . --parallel || goto error
|
cmake --build . --parallel || goto error
|
||||||
ninja install || goto error
|
ninja install || goto error
|
||||||
cd ..\.. || goto error
|
cd ..\.. || goto error
|
||||||
|
@ -103,7 +220,7 @@ rmdir /S /Q "qtimageformats-everywhere-src-%QT%"
|
||||||
cd "qtimageformats-everywhere-src-%QT%" || goto error
|
cd "qtimageformats-everywhere-src-%QT%" || goto error
|
||||||
mkdir build || goto error
|
mkdir build || goto error
|
||||||
cd build || goto error
|
cd build || goto error
|
||||||
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. || goto error
|
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- %FORCEPDB% -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DFEATURE_system_webp=ON || goto error
|
||||||
cmake --build . --parallel || goto error
|
cmake --build . --parallel || goto error
|
||||||
ninja install || goto error
|
ninja install || goto error
|
||||||
cd ..\.. || goto error
|
cd ..\.. || goto error
|
||||||
|
@ -114,7 +231,7 @@ rmdir /S /Q "qtimageformats-everywhere-src-%QT%"
|
||||||
cd "qttools-everywhere-src-%QT%" || goto error
|
cd "qttools-everywhere-src-%QT%" || goto error
|
||||||
mkdir build || goto error
|
mkdir build || goto error
|
||||||
cd build || goto error
|
cd build || goto error
|
||||||
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF || goto error
|
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- %FORCEPDB% -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF || goto error
|
||||||
cmake --build . --parallel || goto error
|
cmake --build . --parallel || goto error
|
||||||
ninja install || goto error
|
ninja install || goto error
|
||||||
cd ..\.. || goto error
|
cd ..\.. || goto error
|
||||||
|
@ -125,11 +242,29 @@ rmdir /S /Q "qttranslations-everywhere-src-%QT%"
|
||||||
cd "qttranslations-everywhere-src-%QT%" || goto error
|
cd "qttranslations-everywhere-src-%QT%" || goto error
|
||||||
mkdir build || goto error
|
mkdir build || goto error
|
||||||
cd build || goto error
|
cd build || goto error
|
||||||
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. || goto error
|
call "%INSTALLDIR%\bin\qt-configure-module.bat" .. -- %FORCEPDB% || goto error
|
||||||
cmake --build . --parallel || goto error
|
cmake --build . --parallel || goto error
|
||||||
ninja install || goto error
|
ninja install || goto error
|
||||||
cd ..\.. || goto error
|
cd ..\.. || goto error
|
||||||
|
|
||||||
|
echo Building shaderc...
|
||||||
|
rmdir /S /Q "shaderc-%SHADERC%"
|
||||||
|
%SEVENZIP% x "shaderc-%SHADERC%.zip" || goto error
|
||||||
|
cd "shaderc-%SHADERC%" || goto error
|
||||||
|
cd third_party || goto error
|
||||||
|
%SEVENZIP% x "..\..\shaderc-glslang-%SHADERC_GLSLANG%.zip" || goto error
|
||||||
|
rename "glslang-%SHADERC_GLSLANG%" "glslang" || goto error
|
||||||
|
%SEVENZIP% x "..\..\shaderc-spirv-headers-%SHADERC_SPIRVHEADERS%.zip" || goto error
|
||||||
|
rename "SPIRV-Headers-%SHADERC_SPIRVHEADERS%" "spirv-headers" || goto error
|
||||||
|
%SEVENZIP% x "..\..\shaderc-spirv-tools-%SHADERC_SPIRVTOOLS%.zip" || goto error
|
||||||
|
rename "SPIRV-Tools-%SHADERC_SPIRVTOOLS%" "spirv-tools" || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
%PATCH% -p1 < "%SCRIPTDIR%\..\common\shaderc-changes.patch" || goto error
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DSHADERC_SKIP_TESTS=ON -DSHADERC_SKIP_EXAMPLES=ON -DSHADERC_SKIP_COPYRIGHT_CHECK=ON -DSHADERC_ENABLE_SHARED_CRT=ON -B build -G Ninja || goto error
|
||||||
|
cmake --build build --parallel || goto error
|
||||||
|
ninja -C build install || goto error
|
||||||
|
cd .. || goto error
|
||||||
|
|
||||||
echo Cleaning up...
|
echo Cleaning up...
|
||||||
cd ..
|
cd ..
|
||||||
rd /S /Q deps-build
|
rd /S /Q deps-build
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
set(CMAKE_CROSSCOMPILING TRUE)
|
||||||
|
set(CMAKE_SYSTEM_NAME Windows)
|
||||||
|
set(CMAKE_SYSTEM_VERSION 10)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR arm64)
|
|
@ -0,0 +1,422 @@
|
||||||
|
diff -ruN jpeg-9f/CMakeLists.txt jpeg-9f-new/CMakeLists.txt
|
||||||
|
--- jpeg-9f/CMakeLists.txt 1970-01-01 10:00:00.000000000 +1000
|
||||||
|
+++ jpeg-9f-new/CMakeLists.txt 2024-03-23 21:29:37.969221600 +1000
|
||||||
|
@@ -0,0 +1,110 @@
|
||||||
|
+# CMake configuration for IJG libjpeg
|
||||||
|
+# Modified from https://github.com/csparker247/jpeg-cmake/blob/develop/resources/CMakeLists.txt
|
||||||
|
+# To install, copy this file and jconfig.h.in into a libjpeg source directory
|
||||||
|
+# Adapted from LuaDist's CMakeLists
|
||||||
|
+# https://github.com/LuaDist/libjpeg/blob/master/CMakeLists.txt
|
||||||
|
+
|
||||||
|
+cmake_minimum_required(VERSION 3.5)
|
||||||
|
+
|
||||||
|
+### Setup the project ###
|
||||||
|
+file(READ "configure.ac" ac)
|
||||||
|
+string(REGEX MATCH "AC_INIT\\(\\[libjpeg\\],\ \\[([0-9]*\\.[0-9]*\\.[0-9]*)\\]\\)" _ ${ac})
|
||||||
|
+set(version ${CMAKE_MATCH_1})
|
||||||
|
+project(libjpeg VERSION ${version} LANGUAGES C)
|
||||||
|
+set(C_STANDARD 99)
|
||||||
|
+
|
||||||
|
+### Include extra packages ###
|
||||||
|
+include(CMakeDependentOption)
|
||||||
|
+include(GNUInstallDirs)
|
||||||
|
+
|
||||||
|
+### Options ###
|
||||||
|
+option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
|
+option(BUILD_STATIC_LIBS "Build static libraries" ON)
|
||||||
|
+
|
||||||
|
+# Make sure we build at least one library
|
||||||
|
+if(NOT(BUILD_SHARED_LIBS OR BUILD_STATIC_LIBS))
|
||||||
|
+ message(FATAL_ERROR "Both static and shared libraries are disabled. Nothing will be built.")
|
||||||
|
+endif()
|
||||||
|
+
|
||||||
|
+### Configure jconfig.h ###
|
||||||
|
+include(ConfigureJConfig.cmake)
|
||||||
|
+
|
||||||
|
+### Build the object library ###
|
||||||
|
+set(PUBLIC_HDRS
|
||||||
|
+ jconfig.h
|
||||||
|
+ jerror.h
|
||||||
|
+ jmorecfg.h
|
||||||
|
+ jpeglib.h
|
||||||
|
+)
|
||||||
|
+
|
||||||
|
+set(SRCS
|
||||||
|
+ jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c
|
||||||
|
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c
|
||||||
|
+ jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c jdarith.c
|
||||||
|
+ jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c jdinput.c
|
||||||
|
+ jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdpostct.c jdsample.c jdtrans.c
|
||||||
|
+ jerror.c jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c
|
||||||
|
+ jmemmgr.c jmemnobs.c jquant1.c jquant2.c jutils.c
|
||||||
|
+)
|
||||||
|
+
|
||||||
|
+### Create static and shared libs ###
|
||||||
|
+if(BUILD_SHARED_LIBS)
|
||||||
|
+ add_library(libjpeg SHARED ${SRCS})
|
||||||
|
+ target_compile_definitions(libjpeg PRIVATE COMPILING_LIBJPEG)
|
||||||
|
+ target_include_directories(libjpeg
|
||||||
|
+ PUBLIC
|
||||||
|
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||||
|
+ $<INSTALL_INTERFACE:include>
|
||||||
|
+ )
|
||||||
|
+ set_target_properties(libjpeg
|
||||||
|
+ PROPERTIES
|
||||||
|
+ VERSION ${PROJECT_VERSION_MAJOR}
|
||||||
|
+ POSITION_INDEPENDENT_CODE ON
|
||||||
|
+ CLEAN_DIRECT_OUTPUT ON
|
||||||
|
+ PUBLIC_HEADER "${PUBLIC_HDRS}"
|
||||||
|
+ )
|
||||||
|
+ install(TARGETS libjpeg
|
||||||
|
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
|
+ )
|
||||||
|
+endif()
|
||||||
|
+
|
||||||
|
+if(BUILD_STATIC_LIBS)
|
||||||
|
+ add_library(libjpeg_static STATIC $<TARGET_OBJECTS:jpeg_objs>)
|
||||||
|
+ target_include_directories(libjpeg_static
|
||||||
|
+ PUBLIC
|
||||||
|
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||||
|
+ $<INSTALL_INTERFACE:include>
|
||||||
|
+ )
|
||||||
|
+ set_target_properties(libjpeg_static
|
||||||
|
+ PROPERTIES
|
||||||
|
+ OUTPUT_NAME jpeg
|
||||||
|
+ VERSION ${PROJECT_VERSION_MAJOR}
|
||||||
|
+ POSITION_INDEPENDENT_CODE ON
|
||||||
|
+ CLEAN_DIRECT_OUTPUT ON
|
||||||
|
+ PUBLIC_HEADER "${PUBLIC_HDRS}"
|
||||||
|
+ )
|
||||||
|
+ install(TARGETS libjpeg_static
|
||||||
|
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
|
+ )
|
||||||
|
+endif()
|
||||||
|
+
|
||||||
|
+# Configure and install pkg-config and libtool files
|
||||||
|
+if(BUILD_STATIC_LIBS OR BUILD_SHARED_LIBS)
|
||||||
|
+ # Compute the la file's weird version number
|
||||||
|
+ math(EXPR JPEG_CONF_VER_MAJOR "${PROJECT_VERSION_MAJOR} + ${PROJECT_VERSION_MINOR}")
|
||||||
|
+ set(JPEG_LIB_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||||
|
+ set(JPEG_LIB_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||||
|
+
|
||||||
|
+ # Configure and install
|
||||||
|
+ configure_file(libjpeg.pc.cmakein libjpeg.pc @ONLY)
|
||||||
|
+ install(FILES
|
||||||
|
+ ${CMAKE_CURRENT_BINARY_DIR}/libjpeg.pc
|
||||||
|
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig
|
||||||
|
+ )
|
||||||
|
+endif()
|
||||||
|
+
|
||||||
|
diff -ruN jpeg-9f/ConfigureJConfig.cmake jpeg-9f-new/ConfigureJConfig.cmake
|
||||||
|
--- jpeg-9f/ConfigureJConfig.cmake 1970-01-01 10:00:00.000000000 +1000
|
||||||
|
+++ jpeg-9f-new/ConfigureJConfig.cmake 2024-03-23 21:09:37.223882900 +1000
|
||||||
|
@@ -0,0 +1,95 @@
|
||||||
|
+include(CheckIncludeFile)
|
||||||
|
+include(CheckSymbolExists)
|
||||||
|
+include(CheckTypeSize)
|
||||||
|
+
|
||||||
|
+# Define this if your system has an ANSI-conforming <stddef.h> file.
|
||||||
|
+check_include_file(stddef.h HAVE_STDDEF_H)
|
||||||
|
+
|
||||||
|
+# Define this if your system has an ANSI-conforming <stdlib.h> file.
|
||||||
|
+check_include_file(stdlib.h HAVE_STDLIB_H)
|
||||||
|
+
|
||||||
|
+# Does your compiler support function prototypes?
|
||||||
|
+# (If not, you also need to use ansi2knr, see install.txt)
|
||||||
|
+set(HAVE_PROTOTYPES true CACHE BOOL "Does your compiler support function prototypes?")
|
||||||
|
+
|
||||||
|
+# Does your compiler support the declaration "unsigned char" ?
|
||||||
|
+# How about "unsigned short" ?
|
||||||
|
+check_type_size("unsigned char" UNSIGNED_CHAR LANGUAGE C)
|
||||||
|
+check_type_size("unsigned short" UNSIGNED_SHORT LANGUAGE C)
|
||||||
|
+
|
||||||
|
+# Define "void" as "char" if your compiler doesn't know about type void.
|
||||||
|
+# NOTE: be sure to define void such that "void *" represents the most general
|
||||||
|
+# pointer type, e.g., that returned by malloc().
|
||||||
|
+# NOT IMPLEMENTED: Modify in jconfig.h.in #
|
||||||
|
+
|
||||||
|
+# Define "const" as empty if your compiler doesn't know the "const" keyword.
|
||||||
|
+# NOT IMPLEMENTED: Modify in jconfig.h.in #
|
||||||
|
+
|
||||||
|
+# Define this if an ordinary "char" type is unsigned.
|
||||||
|
+# If you're not sure, leaving it undefined will work at some cost in speed.
|
||||||
|
+# If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
|
||||||
|
+set(CHAR_IS_UNSIGNED false CACHE BOOL "char type is unsigned")
|
||||||
|
+
|
||||||
|
+# Define this if your system does not have an ANSI/SysV <string.h>,
|
||||||
|
+# but does have a BSD-style <strings.h>.
|
||||||
|
+set(NEED_BSD_STRINGS false CACHE BOOL "Use BSD <strings.h>. Use only if system lacks ANSI/SysV <strings.h>")
|
||||||
|
+
|
||||||
|
+# Define this if your system does not provide typedef size_t in any of the
|
||||||
|
+# ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
|
||||||
|
+# <sys/types.h> instead.
|
||||||
|
+set(NEED_SYS_TYPES_H false CACHE BOOL "size_t defined in <sys/types.h>")
|
||||||
|
+
|
||||||
|
+# For 80x86 machines, you need to define NEED_FAR_POINTERS,
|
||||||
|
+# unless you are using a large-data memory model or 80386 flat-memory mode.
|
||||||
|
+# On less brain-damaged CPUs this symbol must not be defined.
|
||||||
|
+# (Defining this symbol causes large data structures to be referenced through
|
||||||
|
+# "far" pointers and to be allocated with a special version of malloc.)
|
||||||
|
+set(NEED_FAR_POINTERS false CACHE BOOL "Reference large data structures through 'far' pointers allocated with a special version of malloc")
|
||||||
|
+
|
||||||
|
+# Define this if your linker needs global names to be unique in less
|
||||||
|
+# than the first 15 characters.
|
||||||
|
+set(NEED_SHORT_EXTERNAL_NAMES false CACHE BOOL "Global names must be unique in less than the first 15 characters")
|
||||||
|
+
|
||||||
|
+# Although a real ANSI C compiler can deal perfectly well with pointers to
|
||||||
|
+# unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
|
||||||
|
+# and pseudo-ANSI compilers get confused. To keep one of these bozos happy,
|
||||||
|
+# define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you
|
||||||
|
+# actually get "missing structure definition" warnings or errors while
|
||||||
|
+# compiling the JPEG code.
|
||||||
|
+set(INCOMPLETE_TYPES_BROKEN false CACHE BOOL "Disable pointers to unspecified structures")
|
||||||
|
+
|
||||||
|
+# Define "boolean" as unsigned char, not enum, on Windows systems.
|
||||||
|
+# NOT IMPLEMENTED: Modify in jconfig.h.in #
|
||||||
|
+
|
||||||
|
+# The following options affect code selection within the JPEG library,
|
||||||
|
+# but they don't need to be visible to applications using the library.
|
||||||
|
+# To minimize application namespace pollution, the symbols won't be
|
||||||
|
+# defined unless JPEG_INTERNALS has been defined.
|
||||||
|
+#
|
||||||
|
+
|
||||||
|
+# Define this if your compiler implements ">>" on signed values as a logical
|
||||||
|
+# (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
|
||||||
|
+# which is the normal and rational definition.
|
||||||
|
+set(RIGHT_SHIFT_IS_UNSIGNED false CACHE BOOL "Compiler implements >> on signed values as a logical (unsigned) shift")
|
||||||
|
+
|
||||||
|
+# The remaining options do not affect the JPEG library proper,
|
||||||
|
+# but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
|
||||||
|
+# Other applications can ignore these.
|
||||||
|
+#
|
||||||
|
+
|
||||||
|
+mark_as_advanced(FORCE
|
||||||
|
+ HAVE_PROTOTYPES
|
||||||
|
+ HAVE_UNSIGNED_CHAR
|
||||||
|
+ HAVE_UNSIGNED_SHORT
|
||||||
|
+ CHAR_IS_UNSIGNED
|
||||||
|
+ HAVE_STDDEF_H
|
||||||
|
+ HAVE_STDLIB_H
|
||||||
|
+ NEED_BSD_STRINGS
|
||||||
|
+ NEED_SYS_TYPES_H
|
||||||
|
+ NEED_FAR_POINTERS
|
||||||
|
+ NEED_SHORT_EXTERNAL_NAMES
|
||||||
|
+ INCOMPLETE_TYPES_BROKEN
|
||||||
|
+ RIGHT_SHIFT_IS_UNSIGNED
|
||||||
|
+)
|
||||||
|
+
|
||||||
|
+configure_file(jconfig.h.in ${CMAKE_CURRENT_SOURCE_DIR}/jconfig.h)
|
||||||
|
diff -ruN jpeg-9f/jconfig.h.in jpeg-9f-new/jconfig.h.in
|
||||||
|
--- jpeg-9f/jconfig.h.in 1970-01-01 10:00:00.000000000 +1000
|
||||||
|
+++ jpeg-9f-new/jconfig.h.in 2024-03-23 21:06:05.204994600 +1000
|
||||||
|
@@ -0,0 +1,173 @@
|
||||||
|
+/*
|
||||||
|
+ * jconfig.h.in
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 1991-1994, Thomas G. Lane.
|
||||||
|
+ * Modified 2009-2013 by Guido Vollbeding.
|
||||||
|
+ * This file is part of the Independent JPEG Group's software.
|
||||||
|
+ * For conditions of distribution and use, see the accompanying README file.
|
||||||
|
+ *
|
||||||
|
+ * This file is a modification of jconfig.txt from libjpeg. In addition to
|
||||||
|
+ * documenting the configuration options that are required to customize the
|
||||||
|
+ * JPEG software for a particular system, it is used by jpeg-cmake to configure
|
||||||
|
+ * jconfig.h
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * These symbols indicate the properties of your machine or compiler.
|
||||||
|
+ * #define the symbol if yes, #undef it if no.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+/* Does your compiler support function prototypes?
|
||||||
|
+ * (If not, you also need to use ansi2knr, see install.txt)
|
||||||
|
+ */
|
||||||
|
+#cmakedefine HAVE_PROTOTYPES
|
||||||
|
+
|
||||||
|
+/* Does your compiler support the declaration "unsigned char" ?
|
||||||
|
+ * How about "unsigned short" ?
|
||||||
|
+ */
|
||||||
|
+#cmakedefine HAVE_UNSIGNED_CHAR
|
||||||
|
+#cmakedefine HAVE_UNSIGNED_SHORT
|
||||||
|
+
|
||||||
|
+/* Define "void" as "char" if your compiler doesn't know about type void.
|
||||||
|
+ * NOTE: be sure to define void such that "void *" represents the most general
|
||||||
|
+ * pointer type, e.g., that returned by malloc().
|
||||||
|
+ */
|
||||||
|
+/* #define void char */
|
||||||
|
+
|
||||||
|
+/* Define "const" as empty if your compiler doesn't know the "const" keyword.
|
||||||
|
+ */
|
||||||
|
+/* #define const */
|
||||||
|
+
|
||||||
|
+/* Define this if an ordinary "char" type is unsigned.
|
||||||
|
+ * If you're not sure, leaving it undefined will work at some cost in speed.
|
||||||
|
+ * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine CHAR_IS_UNSIGNED
|
||||||
|
+
|
||||||
|
+/* Define this if your system has an ANSI-conforming <stddef.h> file.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine HAVE_STDDEF_H
|
||||||
|
+
|
||||||
|
+/* Define this if your system has an ANSI-conforming <stdlib.h> file.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine HAVE_STDLIB_H
|
||||||
|
+
|
||||||
|
+/* Define this if your system does not have an ANSI/SysV <string.h>,
|
||||||
|
+ * but does have a BSD-style <strings.h>.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine NEED_BSD_STRINGS
|
||||||
|
+
|
||||||
|
+/* Define this if your system does not provide typedef size_t in any of the
|
||||||
|
+ * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
|
||||||
|
+ * <sys/types.h> instead.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine NEED_SYS_TYPES_H
|
||||||
|
+
|
||||||
|
+/* For 80x86 machines, you need to define NEED_FAR_POINTERS,
|
||||||
|
+ * unless you are using a large-data memory model or 80386 flat-memory mode.
|
||||||
|
+ * On less brain-damaged CPUs this symbol must not be defined.
|
||||||
|
+ * (Defining this symbol causes large data structures to be referenced through
|
||||||
|
+ * "far" pointers and to be allocated with a special version of malloc.)
|
||||||
|
+ */
|
||||||
|
+#cmakedefine NEED_FAR_POINTERS
|
||||||
|
+
|
||||||
|
+/* Define this if your linker needs global names to be unique in less
|
||||||
|
+ * than the first 15 characters.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine NEED_SHORT_EXTERNAL_NAMES
|
||||||
|
+
|
||||||
|
+/* Although a real ANSI C compiler can deal perfectly well with pointers to
|
||||||
|
+ * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
|
||||||
|
+ * and pseudo-ANSI compilers get confused. To keep one of these bozos happy,
|
||||||
|
+ * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you
|
||||||
|
+ * actually get "missing structure definition" warnings or errors while
|
||||||
|
+ * compiling the JPEG code.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine INCOMPLETE_TYPES_BROKEN
|
||||||
|
+
|
||||||
|
+/* Define "boolean" as unsigned char, not enum, on Windows systems.
|
||||||
|
+ */
|
||||||
|
+#ifdef _WIN32
|
||||||
|
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
|
||||||
|
+typedef unsigned char boolean;
|
||||||
|
+#endif
|
||||||
|
+#ifndef FALSE /* in case these macros already exist */
|
||||||
|
+#define FALSE 0 /* values of boolean */
|
||||||
|
+#endif
|
||||||
|
+#ifndef TRUE
|
||||||
|
+#define TRUE 1
|
||||||
|
+#endif
|
||||||
|
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * The following options affect code selection within the JPEG library,
|
||||||
|
+ * but they don't need to be visible to applications using the library.
|
||||||
|
+ * To minimize application namespace pollution, the symbols won't be
|
||||||
|
+ * defined unless JPEG_INTERNALS has been defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifdef JPEG_INTERNALS
|
||||||
|
+
|
||||||
|
+/* Define this if your compiler implements ">>" on signed values as a logical
|
||||||
|
+ * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
|
||||||
|
+ * which is the normal and rational definition.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine RIGHT_SHIFT_IS_UNSIGNED
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#endif /* JPEG_INTERNALS */
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * The remaining options do not affect the JPEG library proper,
|
||||||
|
+ * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
|
||||||
|
+ * Other applications can ignore these.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifdef JPEG_CJPEG_DJPEG
|
||||||
|
+
|
||||||
|
+/* These defines indicate which image (non-JPEG) file formats are allowed. */
|
||||||
|
+
|
||||||
|
+#cmakedefine BMP_SUPPORTED /* BMP image file format */
|
||||||
|
+#cmakedefine GIF_SUPPORTED /* GIF image file format */
|
||||||
|
+#cmakedefine PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
|
||||||
|
+#cmakedefine RLE_SUPPORTED /* Utah RLE image file format */
|
||||||
|
+#cmakedefine TARGA_SUPPORTED /* Targa image file format */
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * This defines the default output format for djpeg. Must be one of the FMT_*
|
||||||
|
+ * enums found in djpeg.c or djpegalt.c
|
||||||
|
+ */
|
||||||
|
+#cmakedefine DEFAULT_FMT @DEFAULT_FMT@
|
||||||
|
+
|
||||||
|
+/* Define this if you want to name both input and output files on the command
|
||||||
|
+ * line, rather than using stdout and optionally stdin. You MUST do this if
|
||||||
|
+ * your system can't cope with binary I/O to stdin/stdout. See comments at
|
||||||
|
+ * head of cjpeg.c or djpeg.c.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine TWO_FILE_COMMANDLINE
|
||||||
|
+
|
||||||
|
+/* Define this if your system needs explicit cleanup of temporary files.
|
||||||
|
+ * This is crucial under MS-DOS, where the temporary "files" may be areas
|
||||||
|
+ * of extended memory; on most other systems it's not as important.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine NEED_SIGNAL_CATCHER
|
||||||
|
+
|
||||||
|
+/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb").
|
||||||
|
+ * This is necessary on systems that distinguish text files from binary files,
|
||||||
|
+ * and is harmless on most systems that don't. If you have one of the rare
|
||||||
|
+ * systems that complains about the "b" spec, define this symbol.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine DONT_USE_B_MODE
|
||||||
|
+
|
||||||
|
+/* Define this if you want percent-done progress reports from cjpeg/djpeg.
|
||||||
|
+ */
|
||||||
|
+#cmakedefine PROGRESS_REPORT
|
||||||
|
+
|
||||||
|
+/* Define this if you *don't* want overwrite confirmation */
|
||||||
|
+#cmakedefine NO_OVERWRITE_CHECK
|
||||||
|
+
|
||||||
|
+#endif /* JPEG_CJPEG_DJPEG */
|
||||||
|
diff -ruN jpeg-9f/jmorecfg.h jpeg-9f-new/jmorecfg.h
|
||||||
|
--- jpeg-9f/jmorecfg.h 2022-03-31 19:41:26.000000000 +1000
|
||||||
|
+++ jpeg-9f-new/jmorecfg.h 2024-03-23 21:20:25.514814400 +1000
|
||||||
|
@@ -244,8 +244,13 @@
|
||||||
|
#define LOCAL(type) static type
|
||||||
|
/* a function referenced thru EXTERNs: */
|
||||||
|
#define GLOBAL(type) type
|
||||||
|
+
|
||||||
|
/* a reference to a GLOBAL function: */
|
||||||
|
-#define EXTERN(type) extern type
|
||||||
|
+#ifdef COMPILING_LIBJPEG
|
||||||
|
+#define EXTERN(type) __declspec(dllexport) extern type
|
||||||
|
+#else
|
||||||
|
+#define EXTERN(type) __declspec(dllimport) extern type
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* This macro is used to declare a "method", that is, a function pointer.
|
||||||
|
diff -ruN jpeg-9f/libjpeg.pc.cmakein jpeg-9f-new/libjpeg.pc.cmakein
|
||||||
|
--- jpeg-9f/libjpeg.pc.cmakein 1970-01-01 10:00:00.000000000 +1000
|
||||||
|
+++ jpeg-9f-new/libjpeg.pc.cmakein 2024-03-23 21:06:13.922695100 +1000
|
||||||
|
@@ -0,0 +1,10 @@
|
||||||
|
+prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
+exec_prefix=${prefix}
|
||||||
|
+libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||||
|
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||||
|
+
|
||||||
|
+Name: libjpeg
|
||||||
|
+Description: Reads and writes JPEG files
|
||||||
|
+Version: @JPEG_LIB_VERSION_MAJOR@.@JPEG_LIB_VERSION_MINOR@.0
|
||||||
|
+Libs: -L${libdir} -ljpeg
|
||||||
|
+Cflags: -I${includedir}
|
|
@ -0,0 +1,35 @@
|
||||||
|
--- qtbase/src/3rdparty/pcre2/CMakeLists.txt 2024-03-19 08:46:43.000000000 -0700
|
||||||
|
+++ qtbase/src/3rdparty/pcre2/CMakeLists.txt 2024-06-06 21:52:20.539619500 -0700
|
||||||
|
@@ -41,6 +41,7 @@
|
||||||
|
src/pcre2_xclass.c
|
||||||
|
DEFINES
|
||||||
|
HAVE_CONFIG_H
|
||||||
|
+ PCRE2_DISABLE_JIT
|
||||||
|
PUBLIC_DEFINES
|
||||||
|
PCRE2_CODE_UNIT_WIDTH=16
|
||||||
|
PUBLIC_INCLUDE_DIRECTORIES
|
||||||
|
@@ -52,23 +53,8 @@
|
||||||
|
## Scopes:
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
-qt_internal_extend_target(BundledPcre2 CONDITION QNX OR UIKIT
|
||||||
|
- DEFINES
|
||||||
|
- PCRE2_DISABLE_JIT
|
||||||
|
-)
|
||||||
|
-
|
||||||
|
-qt_internal_extend_target(BundledPcre2 CONDITION (TEST_architecture_arch STREQUAL "arm") AND WIN32
|
||||||
|
- DEFINES
|
||||||
|
- PCRE2_DISABLE_JIT
|
||||||
|
-)
|
||||||
|
-
|
||||||
|
-qt_internal_extend_target(BundledPcre2 CONDITION (TEST_architecture_arch STREQUAL "arm64") AND WIN32
|
||||||
|
- DEFINES
|
||||||
|
- PCRE2_DISABLE_JIT
|
||||||
|
-)
|
||||||
|
-
|
||||||
|
if (APPLE)
|
||||||
|
- target_compile_options(BundledPcre2 PRIVATE "SHELL:-Xarch_arm64 -DPCRE2_DISABLE_JIT")
|
||||||
|
+ target_compile_options(BundledPcre2 PRIVATE "SHELL:-Xarch_arm64")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
qt_internal_extend_target(BundledPcre2 CONDITION WIN32
|
|
@ -0,0 +1,13 @@
|
||||||
|
diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
|
||||||
|
index 208420d7e8..26ef6f31ef 100644
|
||||||
|
--- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
|
||||||
|
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
|
||||||
|
@@ -4232,8 +4232,6 @@ QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption
|
||||||
|
|
||||||
|
case SE_ItemViewItemDecoration:
|
||||||
|
rect = QWindowsStyle::subElementRect(element, option, widget);
|
||||||
|
- if (qstyleoption_cast<const QStyleOptionViewItem *>(option))
|
||||||
|
- rect.adjust(-2, 0, 2, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SE_ItemViewItemFocusRect:
|
|
@ -8,7 +8,7 @@ jobs:
|
||||||
if: github.repository == 'PCSX2/pcsx2'
|
if: github.repository == 'PCSX2/pcsx2'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@main
|
- uses: actions/labeler@v5
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ jobs:
|
||||||
uses: ./.github/workflows/windows_build_qt.yml
|
uses: ./.github/workflows/windows_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "MSVC SSE4"
|
jobName: "MSVC SSE4"
|
||||||
|
artifactPrefixName: "PCSX2-windows-Qt-x64-sse4-msvc"
|
||||||
configuration: Release
|
configuration: Release
|
||||||
simd: "SSE4"
|
simd: "SSE4"
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
@ -38,6 +39,7 @@ jobs:
|
||||||
uses: ./.github/workflows/windows_build_qt.yml
|
uses: ./.github/workflows/windows_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "MSVC AVX2"
|
jobName: "MSVC AVX2"
|
||||||
|
artifactPrefixName: "PCSX2-windows-Qt-x64-avx2-msvc"
|
||||||
configuration: Release AVX2
|
configuration: Release AVX2
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
@ -47,6 +49,7 @@ jobs:
|
||||||
uses: ./.github/workflows/windows_build_qt.yml
|
uses: ./.github/workflows/windows_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "CMake MSVC"
|
jobName: "CMake MSVC"
|
||||||
|
artifactPrefixName: "PCSX2-windows-Qt-x64-cmake-msvc"
|
||||||
configuration: CMake
|
configuration: CMake
|
||||||
buildSystem: cmake
|
buildSystem: cmake
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
@ -58,6 +61,7 @@ jobs:
|
||||||
uses: ./.github/workflows/windows_build_qt.yml
|
uses: ./.github/workflows/windows_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "Clang SSE4"
|
jobName: "Clang SSE4"
|
||||||
|
artifactPrefixName: "PCSX2-windows-Qt-x64-sse4-clang"
|
||||||
configuration: Release Clang
|
configuration: Release Clang
|
||||||
simd: "SSE4"
|
simd: "SSE4"
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
@ -69,6 +73,7 @@ jobs:
|
||||||
uses: ./.github/workflows/windows_build_qt.yml
|
uses: ./.github/workflows/windows_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "Clang AVX2"
|
jobName: "Clang AVX2"
|
||||||
|
artifactPrefixName: "PCSX2-windows-Qt-x64-avx2-clang"
|
||||||
configuration: Release Clang AVX2
|
configuration: Release Clang AVX2
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
@ -78,6 +83,7 @@ jobs:
|
||||||
uses: ./.github/workflows/windows_build_qt.yml
|
uses: ./.github/workflows/windows_build_qt.yml
|
||||||
with:
|
with:
|
||||||
jobName: "CMake Clang"
|
jobName: "CMake Clang"
|
||||||
|
artifactPrefixName: "PCSX2-windows-Qt-x64-cmake-clang"
|
||||||
configuration: CMake
|
configuration: CMake
|
||||||
buildSystem: cmake
|
buildSystem: cmake
|
||||||
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DPCSX2_EXE_NAME=pcsx2-qt-clang
|
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DPCSX2_EXE_NAME=pcsx2-qt-clang
|
||||||
|
|
|
@ -6,6 +6,9 @@ on:
|
||||||
jobName:
|
jobName:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
artifactPrefixName:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
os:
|
os:
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
@ -37,6 +40,10 @@ on:
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
stableBuild:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_windows_qt:
|
build_windows_qt:
|
||||||
|
@ -48,24 +55,30 @@ jobs:
|
||||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Tempfix Clang
|
||||||
|
if: inputs.configuration == 'CMake'
|
||||||
|
run: choco uninstall llvm
|
||||||
|
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
# actions/checkout elides tags, fetch them primarily for releases
|
# actions/checkout elides tags, fetch them primarily for releases
|
||||||
- name: Fetch Tags
|
- name: Fetch Tags
|
||||||
if: ${{ inputs.fetchTags }}
|
if: ${{ inputs.fetchTags }}
|
||||||
run: git fetch --tags --no-recurse-submodules
|
run: git fetch --tags --no-recurse-submodules
|
||||||
|
|
||||||
|
- name: Add stable release identifier file
|
||||||
|
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||||
|
cat ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||||
|
|
||||||
- name: Prepare Artifact Metadata
|
- name: Prepare Artifact Metadata
|
||||||
id: artifact-metadata
|
id: artifact-metadata
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
OS: windows
|
PREFIX: ${{ inputs.artifactPrefixName }}
|
||||||
BUILD_SYSTEM: ${{ inputs.buildSystem }}
|
|
||||||
ARCH: ${{ inputs.platform }}
|
|
||||||
SIMD: ${{ inputs.simd }}
|
|
||||||
EVENT_NAME: ${{ github.event_name }}
|
EVENT_NAME: ${{ github.event_name }}
|
||||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||||
PR_NUM: ${{ github.event.pull_request.number }}
|
PR_NUM: ${{ github.event.pull_request.number }}
|
||||||
|
@ -74,7 +87,7 @@ jobs:
|
||||||
|
|
||||||
- name: Setup msbuild
|
- name: Setup msbuild
|
||||||
if: inputs.configuration != 'CMake'
|
if: inputs.configuration != 'CMake'
|
||||||
uses: microsoft/setup-msbuild@v1
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
- name: Download patches
|
- name: Download patches
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
@ -84,10 +97,10 @@ jobs:
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
id: cache-deps
|
id: cache-deps
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: deps
|
path: deps
|
||||||
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/windows/build-dependencies.bat') }}
|
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/windows/build-dependencies.bat', '.github/workflows/scripts/common/*.patch') }}
|
||||||
|
|
||||||
- name: Build Dependencies
|
- name: Build Dependencies
|
||||||
if: steps.cache-deps.outputs.cache-hit != 'true'
|
if: steps.cache-deps.outputs.cache-hit != 'true'
|
||||||
|
@ -119,10 +132,11 @@ jobs:
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
||||||
|
set PATH=%PATH%;%GITHUB_WORKSPACE%\bin
|
||||||
cmake --build build --config Release --target unittests
|
cmake --build build --config Release --target unittests
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||||
path: |
|
path: |
|
||||||
|
@ -136,7 +150,7 @@ jobs:
|
||||||
!./bin/**/*.lib
|
!./bin/**/*.lib
|
||||||
|
|
||||||
- name: Upload artifact - with symbols
|
- name: Upload artifact - with symbols
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}-symbols
|
name: ${{ steps.artifact-metadata.outputs.artifact-name }}-symbols
|
||||||
path: ./bin/**/*.pdb
|
path: ./bin/**/*.pdb
|
||||||
|
|
|
@ -56,6 +56,14 @@ oprofile_data/
|
||||||
/UpgradeLog*.htm
|
/UpgradeLog*.htm
|
||||||
/.vscode*
|
/.vscode*
|
||||||
|
|
||||||
|
# Jetbrains Rider
|
||||||
|
/.idea*
|
||||||
|
|
||||||
|
# KDevelop 4 Workspace Configuration Files
|
||||||
|
*.kdev4
|
||||||
|
/.kdev4*
|
||||||
|
|
||||||
|
# Resources and docs in /bin are tracked
|
||||||
/bin/**/*.dll
|
/bin/**/*.dll
|
||||||
/bin/**/*.dmp
|
/bin/**/*.dmp
|
||||||
/bin/**/*.exp
|
/bin/**/*.exp
|
||||||
|
@ -67,11 +75,13 @@ oprofile_data/
|
||||||
/bin/bios
|
/bin/bios
|
||||||
/bin/cache
|
/bin/cache
|
||||||
/bin/cheats
|
/bin/cheats
|
||||||
|
/bin/patches
|
||||||
/bin/covers
|
/bin/covers
|
||||||
/bin/dumps
|
/bin/dumps
|
||||||
/bin/gamesettings
|
/bin/gamesettings
|
||||||
/bin/help
|
/bin/help
|
||||||
/bin/inis
|
/bin/inis
|
||||||
|
/bin/inis/debuggersettings
|
||||||
/bin/logs
|
/bin/logs
|
||||||
/bin/memcards
|
/bin/memcards
|
||||||
/bin/plugins
|
/bin/plugins
|
||||||
|
@ -80,7 +90,25 @@ oprofile_data/
|
||||||
/bin/textures
|
/bin/textures
|
||||||
/bin/translations
|
/bin/translations
|
||||||
/bin/inputprofiles
|
/bin/inputprofiles
|
||||||
|
/bin/videos
|
||||||
|
/bin/portable.ini
|
||||||
|
/bin/portable.txt
|
||||||
|
|
||||||
|
# Resources and docs copied from /bin
|
||||||
|
/bin-arm64
|
||||||
|
|
||||||
|
# Manually added by user.
|
||||||
|
/bin/resources/patches.zip
|
||||||
|
|
||||||
|
# Resources that are runtime downloaded.
|
||||||
|
/bin/resources/fonts/NotoSansJP-Regular.ttf
|
||||||
|
/bin/resources/fonts/NotoSansKR-Regular.ttf
|
||||||
|
/bin/resources/fonts/NotoSansSC-Regular.ttf
|
||||||
|
/bin/resources/fonts/NotoSansTC-Regular.ttf
|
||||||
|
|
||||||
|
/deps-build
|
||||||
/deps
|
/deps
|
||||||
|
/deps-arm64
|
||||||
/ipch
|
/ipch
|
||||||
|
|
||||||
!/3rdparty/libjpeg/change.log
|
!/3rdparty/libjpeg/change.log
|
||||||
|
@ -91,3 +119,4 @@ oprofile_data/
|
||||||
CMakeSettings.json
|
CMakeSettings.json
|
||||||
/ci-artifacts/
|
/ci-artifacts/
|
||||||
/out/
|
/out/
|
||||||
|
/.cache/
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
[submodule "3rdparty/xz/xz"]
|
|
||||||
path = 3rdparty/xz/xz
|
|
||||||
url = https://github.com/PCSX2/xz.git
|
|
||||||
[submodule "3rdparty/gtest"]
|
|
||||||
path = 3rdparty/gtest
|
|
||||||
url = https://github.com/google/googletest.git
|
|
||||||
[submodule "3rdparty/fmt/fmt"]
|
|
||||||
path = 3rdparty/fmt/fmt
|
|
||||||
url = https://github.com/fmtlib/fmt.git
|
|
||||||
[submodule "3rdparty/libchdr/libchdr"]
|
|
||||||
path = 3rdparty/libchdr/libchdr
|
|
||||||
url = https://github.com/rtissera/libchdr.git
|
|
||||||
[submodule "3rdparty/wil"]
|
|
||||||
path = 3rdparty/wil
|
|
||||||
url = https://github.com/microsoft/wil.git
|
|
||||||
branch = master
|
|
||||||
[submodule "3rdparty/rapidyaml/rapidyaml"]
|
|
||||||
path = 3rdparty/rapidyaml/rapidyaml
|
|
||||||
url = https://github.com/biojppm/rapidyaml.git
|
|
||||||
branch = master
|
|
||||||
[submodule "3rdparty/glslang/glslang"]
|
|
||||||
path = 3rdparty/glslang/glslang
|
|
||||||
url = https://github.com/KhronosGroup/glslang.git
|
|
||||||
[submodule "3rdparty/vulkan-headers"]
|
|
||||||
path = 3rdparty/vulkan-headers
|
|
||||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
|
||||||
[submodule "3rdparty/zstd/zstd"]
|
|
||||||
path = 3rdparty/zstd/zstd
|
|
||||||
url = https://github.com/facebook/zstd.git
|
|
||||||
[submodule "3rdparty/rcheevos/rcheevos"]
|
|
||||||
path = 3rdparty/rcheevos/rcheevos
|
|
||||||
url = https://github.com/RetroAchievements/rcheevos.git
|
|
|
@ -16,6 +16,23 @@
|
||||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<CompileAs>Default</CompileAs>
|
<CompileAs>Default</CompileAs>
|
||||||
|
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
<MinimalRebuild>false</MinimalRebuild>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
|
||||||
|
<!-- MSVC automatically adds __AVX__ and __AVX2__ appropriately -->
|
||||||
|
<PreprocessorDefinitions>_M_X86;__SSE4_1__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<EnableEnhancedInstructionSet Condition="!$(Configuration.Contains(AVX2)) Or $(Configuration.Contains(Clang))">NotSet</EnableEnhancedInstructionSet>
|
||||||
|
<EnableEnhancedInstructionSet Condition="$(Configuration.Contains(AVX2)) And !$(Configuration.Contains(Clang))">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
<AdditionalOptions Condition="'$(Platform)'=='x64' And $(Configuration.Contains(Clang)) And !$(Configuration.Contains(AVX2))"> -march=nehalem %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalOptions Condition="'$(Platform)'=='x64' And $(Configuration.Contains(Clang)) And $(Configuration.Contains(AVX2))"> -march=haswell %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalOptions Condition="'$(Platform)'=='ARM64' And $(Configuration.Contains(Clang))"> -march=armv8.4-a %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalOptions Condition="!$(Configuration.Contains(Clang))">%(AdditionalOptions) /Zc:externConstexpr /Zc:__cplusplus /Zo /utf-8</AdditionalOptions>
|
||||||
|
|
||||||
|
<!-- Force ThinLTO for Release builds, MSVC doesn't seem to do it otherwise. -->
|
||||||
|
<!-- Also due to include order, needs to be set here, rather than in CodeGen_Release.props -->
|
||||||
|
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Release))"> -flto=thin %(AdditionalOptions)</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
project(ccc)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
add_library(ccc STATIC
|
||||||
|
src/ccc/ast.cpp
|
||||||
|
src/ccc/ast.h
|
||||||
|
src/ccc/elf.cpp
|
||||||
|
src/ccc/elf.h
|
||||||
|
src/ccc/elf_symtab.cpp
|
||||||
|
src/ccc/elf_symtab.h
|
||||||
|
src/ccc/importer_flags.cpp
|
||||||
|
src/ccc/importer_flags.h
|
||||||
|
src/ccc/mdebug_analysis.cpp
|
||||||
|
src/ccc/mdebug_analysis.h
|
||||||
|
src/ccc/mdebug_importer.cpp
|
||||||
|
src/ccc/mdebug_importer.h
|
||||||
|
src/ccc/mdebug_section.cpp
|
||||||
|
src/ccc/mdebug_section.h
|
||||||
|
src/ccc/mdebug_symbols.cpp
|
||||||
|
src/ccc/mdebug_symbols.h
|
||||||
|
src/ccc/sndll.cpp
|
||||||
|
src/ccc/sndll.h
|
||||||
|
src/ccc/stabs.cpp
|
||||||
|
src/ccc/stabs.h
|
||||||
|
src/ccc/stabs_to_ast.cpp
|
||||||
|
src/ccc/stabs_to_ast.h
|
||||||
|
src/ccc/symbol_database.cpp
|
||||||
|
src/ccc/symbol_database.h
|
||||||
|
src/ccc/symbol_file.cpp
|
||||||
|
src/ccc/symbol_file.h
|
||||||
|
src/ccc/symbol_table.cpp
|
||||||
|
src/ccc/symbol_table.h
|
||||||
|
src/ccc/util.cpp
|
||||||
|
src/ccc/util.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(ccc PUBLIC src)
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Chaos Compiler Collection
|
||||||
|
|
||||||
|
This code was originally developed in the following repository and was copied
|
||||||
|
into PCSX2 by the author:
|
||||||
|
|
||||||
|
- [https://github.com/chaoticgd/ccc](https://github.com/chaoticgd/ccc)
|
||||||
|
|
||||||
|
It includes additional resources that are not present in the PCSX2 repository.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### DWARF (.debug) Section
|
||||||
|
|
||||||
|
- [DWARF Debugging Information Format](https://dwarfstd.org/doc/dwarf_1_1_0.pdf)
|
||||||
|
|
||||||
|
### MIPS Debug (.mdebug) Section
|
||||||
|
|
||||||
|
- [Third Eye Software and the MIPS symbol table (Peter Rowell)](http://datahedron.com/mips.html)
|
||||||
|
- [MIPS Mdebug Debugging Information (David Anderson, 1996)](https://www.prevanders.net/Mdebug.ps)
|
||||||
|
- MIPS Assembly Language Programmer's Guide, Symbol Table Chapter (Silicon Graphics, 1992)
|
||||||
|
- Tru64 UNIX Object File and Symbol Table Format Specification, Symbol Table Chapter
|
||||||
|
- `mdebugread.c` from gdb (reading)
|
||||||
|
- `ecoff.c` from gas (writing)
|
||||||
|
- `include/coff/sym.h` from binutils (headers)
|
||||||
|
|
||||||
|
### MIPS EABI
|
||||||
|
|
||||||
|
- [MIPS EABI](https://sourceware.org/legacy-ml/binutils/2003-06/msg00436.html)
|
||||||
|
|
||||||
|
### STABS
|
||||||
|
|
||||||
|
- [The "stabs" representation of debugging information (Julia Menapace, Jim Kingdon, and David MacKenzie, 1992-???)](https://sourceware.org/gdb/onlinedocs/stabs.html)
|
||||||
|
- `stabs.c` from binutils (reading)
|
||||||
|
- `stabsread.c` from gdb (reading)
|
||||||
|
- `dbxread.c` from gdb (reading)
|
||||||
|
- `dbxout.c` from gcc (writing)
|
||||||
|
- `stab.def` from gcc (symbol codes)
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
|
||||||
|
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{2589F8CE-EA77-4B73-911E-64074569795B}</ProjectGuid>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset Condition="!$(Configuration.Contains(Clang))">$(DefaultPlatformToolset)</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="$(Configuration.Contains(Clang))">ClangCL</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
|
||||||
|
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
|
||||||
|
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings" />
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="..\DefaultProjectRootDir.props" />
|
||||||
|
<Import Project="..\3rdparty.props" />
|
||||||
|
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
|
||||||
|
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
|
||||||
|
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
|
||||||
|
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\ccc\ast.h" />
|
||||||
|
<ClInclude Include="src\ccc\elf.h" />
|
||||||
|
<ClInclude Include="src\ccc\elf_symtab.h" />
|
||||||
|
<ClInclude Include="src\ccc\importer_flags.h" />
|
||||||
|
<ClInclude Include="src\ccc\mdebug_analysis.h" />
|
||||||
|
<ClInclude Include="src\ccc\mdebug_importer.h" />
|
||||||
|
<ClInclude Include="src\ccc\mdebug_section.h" />
|
||||||
|
<ClInclude Include="src\ccc\mdebug_symbols.h" />
|
||||||
|
<ClInclude Include="src\ccc\sndll.h" />
|
||||||
|
<ClInclude Include="src\ccc\stabs.h" />
|
||||||
|
<ClInclude Include="src\ccc\stabs_to_ast.h" />
|
||||||
|
<ClInclude Include="src\ccc\symbol_database.h" />
|
||||||
|
<ClInclude Include="src\ccc\symbol_file.h" />
|
||||||
|
<ClInclude Include="src\ccc\symbol_table.h" />
|
||||||
|
<ClInclude Include="src\ccc\util.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\ccc\ast.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\elf.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\elf_symtab.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\importer_flags.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\mdebug_analysis.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\mdebug_importer.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\mdebug_section.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\mdebug_symbols.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\sndll.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\stabs.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\stabs_to_ast.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\symbol_database.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\symbol_file.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\symbol_table.cpp" />
|
||||||
|
<ClCompile Include="src\ccc\util.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\ccc\ast.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\elf.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\elf_symtab.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\importer_flags.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\mdebug_analysis.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\mdebug_importer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\mdebug_section.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\mdebug_symbols.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\sndll.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\stabs.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\stabs_to_ast.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\symbol_database.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\symbol_file.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\symbol_table.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ccc\util.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\ccc\ast.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\elf.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\elf_symtab.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\importer_flags.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\mdebug_analysis.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\mdebug_importer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\mdebug_section.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\mdebug_symbols.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\sndll.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\stabs.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\stabs_to_ast.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\symbol_database.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\symbol_file.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\symbol_table.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ccc\util.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,562 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "ast.h"
|
||||||
|
|
||||||
|
#include "importer_flags.h"
|
||||||
|
#include "symbol_database.h"
|
||||||
|
|
||||||
|
namespace ccc::ast {
|
||||||
|
|
||||||
|
static bool compare_nodes_and_merge(
|
||||||
|
CompareResult& dest, const Node& node_lhs, const Node& node_rhs, const SymbolDatabase* database);
|
||||||
|
static bool try_to_match_wobbly_typedefs(
|
||||||
|
const Node& node_lhs, const Node& node_rhs, const SymbolDatabase& database);
|
||||||
|
|
||||||
|
void Node::set_access_specifier(AccessSpecifier specifier, u32 importer_flags)
|
||||||
|
{
|
||||||
|
if((importer_flags & NO_ACCESS_SPECIFIERS) == 0) {
|
||||||
|
access_specifier = specifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Node*, DataType*> Node::physical_type(SymbolDatabase& database, s32 max_depth)
|
||||||
|
{
|
||||||
|
Node* type = this;
|
||||||
|
DataType* symbol = nullptr;
|
||||||
|
for(s32 i = 0; i < max_depth && type->descriptor == TYPE_NAME; i++) {
|
||||||
|
DataType* data_type = database.data_types.symbol_from_handle(type->as<TypeName>().data_type_handle);
|
||||||
|
if (!data_type || !data_type->type()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = data_type->type();
|
||||||
|
symbol = data_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::pair(type, symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<const Node*, const DataType*> Node::physical_type(const SymbolDatabase& database, s32 max_depth) const
|
||||||
|
{
|
||||||
|
return const_cast<Node*>(this)->physical_type(const_cast<SymbolDatabase&>(database), max_depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* member_function_modifier_to_string(MemberFunctionModifier modifier)
|
||||||
|
{
|
||||||
|
switch(modifier) {
|
||||||
|
case MemberFunctionModifier::NONE: return "none";
|
||||||
|
case MemberFunctionModifier::STATIC: return "static";
|
||||||
|
case MemberFunctionModifier::VIRTUAL: return "virtual";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StructOrUnion::flatten_fields(
|
||||||
|
std::vector<FlatField>& output,
|
||||||
|
const DataType* symbol,
|
||||||
|
const SymbolDatabase& database,
|
||||||
|
bool skip_statics,
|
||||||
|
s32 base_offset,
|
||||||
|
s32 max_fields,
|
||||||
|
s32 max_depth) const
|
||||||
|
{
|
||||||
|
if(max_depth == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const std::unique_ptr<Node>& type_name : base_classes) {
|
||||||
|
if(type_name->descriptor != TYPE_NAME) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 new_base_offset = base_offset + type_name->offset_bytes;
|
||||||
|
|
||||||
|
DataTypeHandle handle = type_name->as<TypeName>().data_type_handle;
|
||||||
|
const DataType* base_class_symbol = database.data_types.symbol_from_handle(handle);
|
||||||
|
if(!base_class_symbol || !base_class_symbol->type() || base_class_symbol->type()->descriptor != STRUCT_OR_UNION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StructOrUnion& base_class = base_class_symbol->type()->as<StructOrUnion>();
|
||||||
|
if(!base_class.flatten_fields(output, base_class_symbol, database, skip_statics, new_base_offset, max_fields, max_depth - 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const std::unique_ptr<Node>& field : fields) {
|
||||||
|
if(skip_statics && field->storage_class == STORAGE_CLASS_STATIC) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((s32) output.size() >= max_fields) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlatField& flat = output.emplace_back();
|
||||||
|
flat.node = field.get();
|
||||||
|
flat.symbol = symbol;
|
||||||
|
flat.base_offset = base_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* type_name_source_to_string(TypeNameSource source)
|
||||||
|
{
|
||||||
|
switch(source) {
|
||||||
|
case TypeNameSource::REFERENCE: return "reference";
|
||||||
|
case TypeNameSource::CROSS_REFERENCE: return "cross_reference";
|
||||||
|
case TypeNameSource::UNNAMED_THIS: return "this";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* forward_declared_type_to_string(ForwardDeclaredType type)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case ForwardDeclaredType::STRUCT: return "struct";
|
||||||
|
case ForwardDeclaredType::UNION: return "union";
|
||||||
|
case ForwardDeclaredType::ENUM: return "enum";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypeHandle TypeName::data_type_handle_unless_forward_declared() const
|
||||||
|
{
|
||||||
|
if(!is_forward_declared) {
|
||||||
|
return data_type_handle;
|
||||||
|
} else {
|
||||||
|
return DataTypeHandle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompareResult compare_nodes(
|
||||||
|
const Node& node_lhs, const Node& node_rhs, const SymbolDatabase* database, bool check_intrusive_fields)
|
||||||
|
{
|
||||||
|
CompareResult result = CompareResultType::MATCHES_NO_SWAP;
|
||||||
|
|
||||||
|
if(node_lhs.descriptor != node_rhs.descriptor) {
|
||||||
|
return CompareFailReason::DESCRIPTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(check_intrusive_fields) {
|
||||||
|
if(node_lhs.storage_class != node_rhs.storage_class) {
|
||||||
|
// In some cases we can determine that a type was typedef'd for C
|
||||||
|
// translation units, but not for C++ translation units, so we need
|
||||||
|
// to add a special case for that here.
|
||||||
|
if(node_lhs.storage_class == STORAGE_CLASS_TYPEDEF && node_rhs.storage_class == STORAGE_CLASS_NONE) {
|
||||||
|
result = CompareResultType::MATCHES_FAVOUR_LHS;
|
||||||
|
} else if(node_lhs.storage_class == STORAGE_CLASS_NONE && node_rhs.storage_class == STORAGE_CLASS_TYPEDEF) {
|
||||||
|
result = CompareResultType::MATCHES_FAVOUR_RHS;
|
||||||
|
} else {
|
||||||
|
return CompareFailReason::STORAGE_CLASS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vtable pointers and constructors can sometimes contain type numbers
|
||||||
|
// that are different between translation units, so we don't want to
|
||||||
|
// compare them.
|
||||||
|
bool is_vtable_pointer = node_lhs.is_vtable_pointer && node_rhs.is_vtable_pointer;
|
||||||
|
bool is_numbered_constructor = node_lhs.name.starts_with("$_") && node_rhs.name.starts_with("$_");
|
||||||
|
if(node_lhs.name != node_rhs.name && !is_vtable_pointer && !is_numbered_constructor) {
|
||||||
|
return CompareFailReason::NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node_lhs.offset_bytes != node_rhs.offset_bytes) {
|
||||||
|
return CompareFailReason::RELATIVE_OFFSET_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node_lhs.size_bits != node_rhs.size_bits) {
|
||||||
|
return CompareFailReason::SIZE_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node_lhs.is_const != node_rhs.is_const) {
|
||||||
|
return CompareFailReason::CONSTNESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(node_lhs.descriptor) {
|
||||||
|
case ARRAY: {
|
||||||
|
const auto [lhs, rhs] = Node::as<Array>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.element_type.get(), *rhs.element_type.get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lhs.element_count != rhs.element_count) {
|
||||||
|
return CompareFailReason::ARRAY_ELEMENT_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BITFIELD: {
|
||||||
|
const auto [lhs, rhs] = Node::as<BitField>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
if(lhs.bitfield_offset_bits != rhs.bitfield_offset_bits) {
|
||||||
|
return CompareFailReason::BITFIELD_OFFSET_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.underlying_type.get(), *rhs.underlying_type.get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BUILTIN: {
|
||||||
|
const auto [lhs, rhs] = Node::as<BuiltIn>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
if(lhs.bclass != rhs.bclass) {
|
||||||
|
return CompareFailReason::BUILTIN_CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ENUM: {
|
||||||
|
const auto [lhs, rhs] = Node::as<Enum>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
if(lhs.constants != rhs.constants) {
|
||||||
|
return CompareFailReason::ENUM_CONSTANTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ERROR_NODE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FUNCTION: {
|
||||||
|
const auto [lhs, rhs] = Node::as<Function>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
if(lhs.return_type.has_value() != rhs.return_type.has_value()) {
|
||||||
|
return CompareFailReason::FUNCTION_RETURN_TYPE_HAS_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lhs.return_type.has_value()) {
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.return_type->get(), *rhs.return_type->get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lhs.parameters.has_value() && rhs.parameters.has_value()) {
|
||||||
|
if(lhs.parameters->size() != rhs.parameters->size()) {
|
||||||
|
return CompareFailReason::FUNCTION_PARAMAETER_COUNT;
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < lhs.parameters->size(); i++) {
|
||||||
|
if(compare_nodes_and_merge(result, *(*lhs.parameters)[i].get(), *(*rhs.parameters)[i].get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(lhs.parameters.has_value() != rhs.parameters.has_value()) {
|
||||||
|
return CompareFailReason::FUNCTION_PARAMETERS_HAS_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lhs.modifier != rhs.modifier) {
|
||||||
|
return CompareFailReason::FUNCTION_MODIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case POINTER_OR_REFERENCE: {
|
||||||
|
const auto [lhs, rhs] = Node::as<PointerOrReference>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
if(lhs.is_pointer != rhs.is_pointer) {
|
||||||
|
return CompareFailReason::DESCRIPTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.value_type.get(), *rhs.value_type.get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case POINTER_TO_DATA_MEMBER: {
|
||||||
|
const auto [lhs, rhs] = Node::as<PointerToDataMember>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.class_type.get(), *rhs.class_type.get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.member_type.get(), *rhs.member_type.get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STRUCT_OR_UNION: {
|
||||||
|
const auto [lhs, rhs] = Node::as<StructOrUnion>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
if(lhs.is_struct != rhs.is_struct) {
|
||||||
|
return CompareFailReason::DESCRIPTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lhs.base_classes.size() != rhs.base_classes.size()) {
|
||||||
|
return CompareFailReason::BASE_CLASS_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < lhs.base_classes.size(); i++) {
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.base_classes[i].get(), *rhs.base_classes[i].get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lhs.fields.size() != rhs.fields.size()) {
|
||||||
|
return CompareFailReason::FIELDS_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < lhs.fields.size(); i++) {
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.fields[i].get(), *rhs.fields[i].get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lhs.member_functions.size() != rhs.member_functions.size()) {
|
||||||
|
return CompareFailReason::MEMBER_FUNCTION_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < lhs.member_functions.size(); i++) {
|
||||||
|
if(compare_nodes_and_merge(result, *lhs.member_functions[i].get(), *rhs.member_functions[i].get(), database)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_NAME: {
|
||||||
|
const auto [lhs, rhs] = Node::as<TypeName>(node_lhs, node_rhs);
|
||||||
|
|
||||||
|
// Don't check the source so that REFERENCE and CROSS_REFERENCE are
|
||||||
|
// treated as the same.
|
||||||
|
if(lhs.data_type_handle != rhs.data_type_handle) {
|
||||||
|
return CompareFailReason::TYPE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeName::UnresolvedStabs* lhs_unresolved_stabs = lhs.unresolved_stabs.get();
|
||||||
|
const TypeName::UnresolvedStabs* rhs_unresolved_stabs = rhs.unresolved_stabs.get();
|
||||||
|
if(lhs_unresolved_stabs && rhs_unresolved_stabs) {
|
||||||
|
if(lhs_unresolved_stabs->type_name != rhs_unresolved_stabs->type_name) {
|
||||||
|
return CompareFailReason::TYPE_NAME;
|
||||||
|
}
|
||||||
|
} else if(lhs_unresolved_stabs || rhs_unresolved_stabs) {
|
||||||
|
return CompareFailReason::TYPE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool compare_nodes_and_merge(
|
||||||
|
CompareResult& dest, const Node& node_lhs, const Node& node_rhs, const SymbolDatabase* database)
|
||||||
|
{
|
||||||
|
CompareResult result = compare_nodes(node_lhs, node_rhs, database, true);
|
||||||
|
if(database) {
|
||||||
|
if(result.type == CompareResultType::DIFFERS && try_to_match_wobbly_typedefs(node_lhs, node_rhs, *database)) {
|
||||||
|
result.type = CompareResultType::MATCHES_FAVOUR_LHS;
|
||||||
|
} else if(result.type == CompareResultType::DIFFERS && try_to_match_wobbly_typedefs(node_rhs, node_lhs, *database)) {
|
||||||
|
result.type = CompareResultType::MATCHES_FAVOUR_RHS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dest.type != result.type) {
|
||||||
|
if(dest.type == CompareResultType::DIFFERS || result.type == CompareResultType::DIFFERS) {
|
||||||
|
// If any of the inner types differ, the outer type does too.
|
||||||
|
dest.type = CompareResultType::DIFFERS;
|
||||||
|
} else if(dest.type == CompareResultType::MATCHES_CONFUSED || result.type == CompareResultType::MATCHES_CONFUSED) {
|
||||||
|
// Propagate confusion.
|
||||||
|
dest.type = CompareResultType::MATCHES_CONFUSED;
|
||||||
|
} else if(dest.type == CompareResultType::MATCHES_FAVOUR_LHS && result.type == CompareResultType::MATCHES_FAVOUR_RHS) {
|
||||||
|
// One of the results favours the LHS node and the other favours the
|
||||||
|
// RHS node so we are confused.
|
||||||
|
dest.type = CompareResultType::MATCHES_CONFUSED;
|
||||||
|
} else if(dest.type == CompareResultType::MATCHES_FAVOUR_RHS && result.type == CompareResultType::MATCHES_FAVOUR_LHS) {
|
||||||
|
// One of the results favours the LHS node and the other favours the
|
||||||
|
// RHS node so we are confused.
|
||||||
|
dest.type = CompareResultType::MATCHES_CONFUSED;
|
||||||
|
} else if(dest.type == CompareResultType::MATCHES_FAVOUR_LHS || result.type == CompareResultType::MATCHES_FAVOUR_LHS) {
|
||||||
|
// One of the results favours the LHS node and the other is neutral
|
||||||
|
// so go with the LHS node.
|
||||||
|
dest.type = CompareResultType::MATCHES_FAVOUR_LHS;
|
||||||
|
} else if(dest.type == CompareResultType::MATCHES_FAVOUR_RHS || result.type == CompareResultType::MATCHES_FAVOUR_RHS) {
|
||||||
|
// One of the results favours the RHS node and the other is neutral
|
||||||
|
// so go with the RHS node.
|
||||||
|
dest.type = CompareResultType::MATCHES_FAVOUR_RHS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dest.fail_reason == CompareFailReason::NONE) {
|
||||||
|
dest.fail_reason = result.fail_reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest.type == CompareResultType::DIFFERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool try_to_match_wobbly_typedefs(
|
||||||
|
const Node& type_name_node, const Node& raw_node, const SymbolDatabase& database)
|
||||||
|
{
|
||||||
|
// Detect if one side has a typedef when the other just has the plain type.
|
||||||
|
// This was previously a common reason why type deduplication would fail.
|
||||||
|
if(type_name_node.descriptor != TYPE_NAME) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeName& type_name = type_name_node.as<TypeName>();
|
||||||
|
if(const TypeName::UnresolvedStabs* unresolved_stabs = type_name.unresolved_stabs.get()) {
|
||||||
|
if(unresolved_stabs->referenced_file_handle == (u32) -1 || !unresolved_stabs->stabs_type_number.valid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SourceFile* source_file =
|
||||||
|
database.source_files.symbol_from_handle(unresolved_stabs->referenced_file_handle);
|
||||||
|
CCC_ASSERT(source_file);
|
||||||
|
|
||||||
|
auto handle = source_file->stabs_type_number_to_handle.find(unresolved_stabs->stabs_type_number);
|
||||||
|
if(handle != source_file->stabs_type_number_to_handle.end()) {
|
||||||
|
const DataType* referenced_type = database.data_types.symbol_from_handle(handle->second);
|
||||||
|
CCC_ASSERT(referenced_type && referenced_type->type());
|
||||||
|
// Don't compare 'intrusive' fields e.g. the offset.
|
||||||
|
CompareResult new_result = compare_nodes(*referenced_type->type(), raw_node, &database, false);
|
||||||
|
if(new_result.type != CompareResultType::DIFFERS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* compare_fail_reason_to_string(CompareFailReason reason)
|
||||||
|
{
|
||||||
|
switch(reason) {
|
||||||
|
case CompareFailReason::NONE: return "error";
|
||||||
|
case CompareFailReason::DESCRIPTOR: return "descriptor";
|
||||||
|
case CompareFailReason::STORAGE_CLASS: return "storage class";
|
||||||
|
case CompareFailReason::NAME: return "name";
|
||||||
|
case CompareFailReason::RELATIVE_OFFSET_BYTES: return "relative offset";
|
||||||
|
case CompareFailReason::ABSOLUTE_OFFSET_BYTES: return "absolute offset";
|
||||||
|
case CompareFailReason::BITFIELD_OFFSET_BITS: return "bitfield offset";
|
||||||
|
case CompareFailReason::SIZE_BITS: return "size";
|
||||||
|
case CompareFailReason::CONSTNESS: return "constness";
|
||||||
|
case CompareFailReason::ARRAY_ELEMENT_COUNT: return "array element count";
|
||||||
|
case CompareFailReason::BUILTIN_CLASS: return "builtin class";
|
||||||
|
case CompareFailReason::FUNCTION_RETURN_TYPE_HAS_VALUE: return "function return type has value";
|
||||||
|
case CompareFailReason::FUNCTION_PARAMAETER_COUNT: return "function paramaeter count";
|
||||||
|
case CompareFailReason::FUNCTION_PARAMETERS_HAS_VALUE: return "function parameter";
|
||||||
|
case CompareFailReason::FUNCTION_MODIFIER: return "function modifier";
|
||||||
|
case CompareFailReason::ENUM_CONSTANTS: return "enum constant";
|
||||||
|
case CompareFailReason::BASE_CLASS_COUNT: return "base class count";
|
||||||
|
case CompareFailReason::FIELDS_SIZE: return "fields size";
|
||||||
|
case CompareFailReason::MEMBER_FUNCTION_COUNT: return "member function count";
|
||||||
|
case CompareFailReason::VTABLE_GLOBAL: return "vtable global";
|
||||||
|
case CompareFailReason::TYPE_NAME: return "type name";
|
||||||
|
case CompareFailReason::VARIABLE_CLASS: return "variable class";
|
||||||
|
case CompareFailReason::VARIABLE_TYPE: return "variable type";
|
||||||
|
case CompareFailReason::VARIABLE_STORAGE: return "variable storage";
|
||||||
|
case CompareFailReason::VARIABLE_BLOCK: return "variable block";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* node_type_to_string(const Node& node)
|
||||||
|
{
|
||||||
|
switch(node.descriptor) {
|
||||||
|
case ARRAY: return "array";
|
||||||
|
case BITFIELD: return "bitfield";
|
||||||
|
case BUILTIN: return "builtin";
|
||||||
|
case ENUM: return "enum";
|
||||||
|
case ERROR_NODE: return "error";
|
||||||
|
case FUNCTION: return "function";
|
||||||
|
case POINTER_OR_REFERENCE: {
|
||||||
|
const PointerOrReference& pointer_or_reference = node.as<PointerOrReference>();
|
||||||
|
if(pointer_or_reference.is_pointer) {
|
||||||
|
return "pointer";
|
||||||
|
} else {
|
||||||
|
return "reference";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case POINTER_TO_DATA_MEMBER: return "pointer_to_data_member";
|
||||||
|
case STRUCT_OR_UNION: {
|
||||||
|
const StructOrUnion& struct_or_union = node.as<StructOrUnion>();
|
||||||
|
if(struct_or_union.is_struct) {
|
||||||
|
return "struct";
|
||||||
|
} else {
|
||||||
|
return "union";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case TYPE_NAME: return "type_name";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* storage_class_to_string(StorageClass storage_class)
|
||||||
|
{
|
||||||
|
switch(storage_class) {
|
||||||
|
case STORAGE_CLASS_NONE: return "none";
|
||||||
|
case STORAGE_CLASS_TYPEDEF: return "typedef";
|
||||||
|
case STORAGE_CLASS_EXTERN: return "extern";
|
||||||
|
case STORAGE_CLASS_STATIC: return "static";
|
||||||
|
case STORAGE_CLASS_AUTO: return "auto";
|
||||||
|
case STORAGE_CLASS_REGISTER: return "register";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* access_specifier_to_string(AccessSpecifier specifier)
|
||||||
|
{
|
||||||
|
switch(specifier) {
|
||||||
|
case AS_PUBLIC: return "public";
|
||||||
|
case AS_PROTECTED: return "protected";
|
||||||
|
case AS_PRIVATE: return "private";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* builtin_class_to_string(BuiltInClass bclass)
|
||||||
|
{
|
||||||
|
switch(bclass) {
|
||||||
|
case BuiltInClass::VOID_TYPE: return "void";
|
||||||
|
case BuiltInClass::UNSIGNED_8: return "8-bit unsigned integer";
|
||||||
|
case BuiltInClass::SIGNED_8: return "8-bit signed integer";
|
||||||
|
case BuiltInClass::UNQUALIFIED_8: return "8-bit integer";
|
||||||
|
case BuiltInClass::BOOL_8: return "8-bit boolean";
|
||||||
|
case BuiltInClass::UNSIGNED_16: return "16-bit unsigned integer";
|
||||||
|
case BuiltInClass::SIGNED_16: return "16-bit signed integer";
|
||||||
|
case BuiltInClass::UNSIGNED_32: return "32-bit unsigned integer";
|
||||||
|
case BuiltInClass::SIGNED_32: return "32-bit signed integer";
|
||||||
|
case BuiltInClass::FLOAT_32: return "32-bit floating point";
|
||||||
|
case BuiltInClass::UNSIGNED_64: return "64-bit unsigned integer";
|
||||||
|
case BuiltInClass::SIGNED_64: return "64-bit signed integer";
|
||||||
|
case BuiltInClass::FLOAT_64: return "64-bit floating point";
|
||||||
|
case BuiltInClass::UNSIGNED_128: return "128-bit unsigned integer";
|
||||||
|
case BuiltInClass::SIGNED_128: return "128-bit signed integer";
|
||||||
|
case BuiltInClass::UNQUALIFIED_128: return "128-bit integer";
|
||||||
|
case BuiltInClass::FLOAT_128: return "128-bit floating point";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 builtin_class_size(BuiltInClass bclass)
|
||||||
|
{
|
||||||
|
switch(bclass) {
|
||||||
|
case BuiltInClass::VOID_TYPE: return 0;
|
||||||
|
case BuiltInClass::UNSIGNED_8: return 1;
|
||||||
|
case BuiltInClass::SIGNED_8: return 1;
|
||||||
|
case BuiltInClass::UNQUALIFIED_8: return 1;
|
||||||
|
case BuiltInClass::BOOL_8: return 1;
|
||||||
|
case BuiltInClass::UNSIGNED_16: return 2;
|
||||||
|
case BuiltInClass::SIGNED_16: return 2;
|
||||||
|
case BuiltInClass::UNSIGNED_32: return 4;
|
||||||
|
case BuiltInClass::SIGNED_32: return 4;
|
||||||
|
case BuiltInClass::FLOAT_32: return 4;
|
||||||
|
case BuiltInClass::UNSIGNED_64: return 8;
|
||||||
|
case BuiltInClass::SIGNED_64: return 8;
|
||||||
|
case BuiltInClass::FLOAT_64: return 8;
|
||||||
|
case BuiltInClass::UNSIGNED_128: return 16;
|
||||||
|
case BuiltInClass::SIGNED_128: return 16;
|
||||||
|
case BuiltInClass::UNQUALIFIED_128: return 16;
|
||||||
|
case BuiltInClass::FLOAT_128: return 16;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,377 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "symbol_database.h"
|
||||||
|
|
||||||
|
namespace ccc::ast {
|
||||||
|
|
||||||
|
enum NodeDescriptor : u8 {
|
||||||
|
ARRAY,
|
||||||
|
BITFIELD,
|
||||||
|
BUILTIN,
|
||||||
|
ENUM,
|
||||||
|
ERROR_NODE,
|
||||||
|
FUNCTION,
|
||||||
|
POINTER_OR_REFERENCE,
|
||||||
|
POINTER_TO_DATA_MEMBER,
|
||||||
|
STRUCT_OR_UNION,
|
||||||
|
TYPE_NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AccessSpecifier {
|
||||||
|
AS_PUBLIC = 0,
|
||||||
|
AS_PROTECTED = 1,
|
||||||
|
AS_PRIVATE = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// To add a new type of node:
|
||||||
|
// 1. Add it to the NodeDescriptor enum.
|
||||||
|
// 2. Create a struct for it.
|
||||||
|
// 3. Add support for it in for_each_node.
|
||||||
|
// 4. Add support for it in compute_size_bytes_recursive.
|
||||||
|
// 5. Add support for it in compare_nodes.
|
||||||
|
// 6. Add support for it in node_type_to_string.
|
||||||
|
// 7. Add support for it in CppPrinter::ast_node.
|
||||||
|
// 8. Add support for it in write_json.
|
||||||
|
// 9. Add support for it in refine_node.
|
||||||
|
struct Node {
|
||||||
|
const NodeDescriptor descriptor;
|
||||||
|
u8 is_const : 1 = false;
|
||||||
|
u8 is_volatile : 1 = false;
|
||||||
|
u8 is_virtual_base_class : 1 = false;
|
||||||
|
u8 is_vtable_pointer : 1 = false;
|
||||||
|
u8 is_constructor_or_destructor : 1 = false;
|
||||||
|
u8 is_special_member_function : 1 = false;
|
||||||
|
u8 is_operator_member_function : 1 = false;
|
||||||
|
u8 cannot_compute_size : 1 = false;
|
||||||
|
u8 storage_class : 4 = STORAGE_CLASS_NONE;
|
||||||
|
u8 access_specifier : 2 = AS_PUBLIC;
|
||||||
|
|
||||||
|
s32 size_bytes = -1;
|
||||||
|
|
||||||
|
// If the name isn't populated for a given node, the name from the last
|
||||||
|
// ancestor to have one should be used i.e. when processing the tree you
|
||||||
|
// should pass the name down.
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
s32 offset_bytes = -1; // Offset relative to start of last inline struct/union.
|
||||||
|
s32 size_bits = -1; // Size stored in the .mdebug symbol table, may not be set.
|
||||||
|
|
||||||
|
Node(NodeDescriptor d) : descriptor(d) {}
|
||||||
|
Node(const Node& rhs) = default;
|
||||||
|
virtual ~Node() {}
|
||||||
|
|
||||||
|
template <typename SubType>
|
||||||
|
SubType& as() {
|
||||||
|
CCC_ASSERT(descriptor == SubType::DESCRIPTOR);
|
||||||
|
return *static_cast<SubType*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename SubType>
|
||||||
|
const SubType& as() const {
|
||||||
|
CCC_ASSERT(descriptor == SubType::DESCRIPTOR);
|
||||||
|
return *static_cast<const SubType*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename SubType>
|
||||||
|
static std::pair<const SubType&, const SubType&> as(const Node& lhs, const Node& rhs) {
|
||||||
|
CCC_ASSERT(lhs.descriptor == SubType::DESCRIPTOR && rhs.descriptor == SubType::DESCRIPTOR);
|
||||||
|
return std::pair<const SubType&, const SubType&>(static_cast<const SubType&>(lhs), static_cast<const SubType&>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_access_specifier(AccessSpecifier specifier, u32 importer_flags);
|
||||||
|
|
||||||
|
// If this node is a type name, repeatedly resolve it to the type it's
|
||||||
|
// referencing, otherwise return (this, nullptr).
|
||||||
|
std::pair<Node*, DataType*> physical_type(SymbolDatabase& database, s32 max_depth = 100);
|
||||||
|
std::pair<const Node*, const DataType*> physical_type(const SymbolDatabase& database, s32 max_depth = 100) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Array : Node {
|
||||||
|
std::unique_ptr<Node> element_type;
|
||||||
|
s32 element_count = -1;
|
||||||
|
|
||||||
|
Array() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = ARRAY;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BitField : Node {
|
||||||
|
s32 bitfield_offset_bits = -1; // Offset relative to the last byte (not the position of the underlying type!).
|
||||||
|
std::unique_ptr<Node> underlying_type;
|
||||||
|
|
||||||
|
BitField() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = BITFIELD;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BuiltInClass {
|
||||||
|
VOID_TYPE,
|
||||||
|
UNSIGNED_8, SIGNED_8, UNQUALIFIED_8, BOOL_8,
|
||||||
|
UNSIGNED_16, SIGNED_16,
|
||||||
|
UNSIGNED_32, SIGNED_32, FLOAT_32,
|
||||||
|
UNSIGNED_64, SIGNED_64, FLOAT_64,
|
||||||
|
UNSIGNED_128, SIGNED_128, UNQUALIFIED_128, FLOAT_128
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuiltIn : Node {
|
||||||
|
BuiltInClass bclass = BuiltInClass::VOID_TYPE;
|
||||||
|
|
||||||
|
BuiltIn() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = BUILTIN;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Enum : Node {
|
||||||
|
std::vector<std::pair<s32, std::string>> constants;
|
||||||
|
|
||||||
|
Enum() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = ENUM;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Error : Node {
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
Error() : Node(ERROR_NODE) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = ERROR_NODE;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MemberFunctionModifier {
|
||||||
|
NONE,
|
||||||
|
STATIC,
|
||||||
|
VIRTUAL
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* member_function_modifier_to_string(MemberFunctionModifier modifier);
|
||||||
|
|
||||||
|
struct Function : Node {
|
||||||
|
std::optional<std::unique_ptr<Node>> return_type;
|
||||||
|
std::optional<std::vector<std::unique_ptr<Node>>> parameters;
|
||||||
|
MemberFunctionModifier modifier = MemberFunctionModifier::NONE;
|
||||||
|
s32 vtable_index = -1;
|
||||||
|
FunctionHandle definition_handle; // Filled in by fill_in_pointers_to_member_function_definitions.
|
||||||
|
|
||||||
|
Function() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = FUNCTION;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PointerOrReference : Node {
|
||||||
|
bool is_pointer = true;
|
||||||
|
std::unique_ptr<Node> value_type;
|
||||||
|
|
||||||
|
PointerOrReference() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = POINTER_OR_REFERENCE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PointerToDataMember : Node {
|
||||||
|
std::unique_ptr<Node> class_type;
|
||||||
|
std::unique_ptr<Node> member_type;
|
||||||
|
|
||||||
|
PointerToDataMember() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = POINTER_TO_DATA_MEMBER;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StructOrUnion : Node {
|
||||||
|
bool is_struct = true;
|
||||||
|
std::vector<std::unique_ptr<Node>> base_classes;
|
||||||
|
std::vector<std::unique_ptr<Node>> fields;
|
||||||
|
std::vector<std::unique_ptr<Node>> member_functions;
|
||||||
|
|
||||||
|
StructOrUnion() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = STRUCT_OR_UNION;
|
||||||
|
|
||||||
|
struct FlatField {
|
||||||
|
// The field itself.
|
||||||
|
const Node* node;
|
||||||
|
// The symbol that owns the node.
|
||||||
|
const DataType* symbol;
|
||||||
|
// Offset of the innermost enclosing base class in the object.
|
||||||
|
s32 base_offset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate a flat list of all the fields in this class as well as all the
|
||||||
|
// base classes recursively, but only until the max_fields or max_depth
|
||||||
|
// limits are reached. Return true if all the fields were enumerated.
|
||||||
|
bool flatten_fields(
|
||||||
|
std::vector<FlatField>& output,
|
||||||
|
const DataType* symbol,
|
||||||
|
const SymbolDatabase& database,
|
||||||
|
bool skip_statics,
|
||||||
|
s32 base_offset = 0,
|
||||||
|
s32 max_fields = 100000,
|
||||||
|
s32 max_depth = 100) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TypeNameSource : u8 {
|
||||||
|
REFERENCE, // A STABS type reference.
|
||||||
|
CROSS_REFERENCE, // A STABS cross reference.
|
||||||
|
UNNAMED_THIS // A this parameter (or return type) referencing an unnamed type.
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* type_name_source_to_string(TypeNameSource source);
|
||||||
|
|
||||||
|
enum class ForwardDeclaredType {
|
||||||
|
STRUCT,
|
||||||
|
UNION,
|
||||||
|
ENUM // Should be illegal but STABS supports cross references to enums so it's here.
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* forward_declared_type_to_string(ForwardDeclaredType type);
|
||||||
|
|
||||||
|
struct TypeName : Node {
|
||||||
|
DataTypeHandle data_type_handle;
|
||||||
|
TypeNameSource source = TypeNameSource::REFERENCE;
|
||||||
|
bool is_forward_declared = false;
|
||||||
|
|
||||||
|
DataTypeHandle data_type_handle_unless_forward_declared() const;
|
||||||
|
|
||||||
|
struct UnresolvedStabs {
|
||||||
|
std::string type_name;
|
||||||
|
SourceFileHandle referenced_file_handle;
|
||||||
|
StabsTypeNumber stabs_type_number;
|
||||||
|
std::optional<ForwardDeclaredType> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<UnresolvedStabs> unresolved_stabs;
|
||||||
|
|
||||||
|
TypeName() : Node(DESCRIPTOR) {}
|
||||||
|
static const constexpr NodeDescriptor DESCRIPTOR = TYPE_NAME;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CompareResultType {
|
||||||
|
MATCHES_NO_SWAP, // Both lhs and rhs are identical.
|
||||||
|
MATCHES_CONFUSED, // Both lhs and rhs are almost identical, and we don't which is better.
|
||||||
|
MATCHES_FAVOUR_LHS, // Both lhs and rhs are almost identical, but lhs is better.
|
||||||
|
MATCHES_FAVOUR_RHS, // Both lhs and rhs are almost identical, but rhs is better.
|
||||||
|
DIFFERS, // The two nodes differ substantially.
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CompareFailReason {
|
||||||
|
NONE,
|
||||||
|
DESCRIPTOR,
|
||||||
|
STORAGE_CLASS,
|
||||||
|
NAME,
|
||||||
|
RELATIVE_OFFSET_BYTES,
|
||||||
|
ABSOLUTE_OFFSET_BYTES,
|
||||||
|
BITFIELD_OFFSET_BITS,
|
||||||
|
SIZE_BITS,
|
||||||
|
CONSTNESS,
|
||||||
|
ARRAY_ELEMENT_COUNT,
|
||||||
|
BUILTIN_CLASS,
|
||||||
|
FUNCTION_RETURN_TYPE_HAS_VALUE,
|
||||||
|
FUNCTION_PARAMAETER_COUNT,
|
||||||
|
FUNCTION_PARAMETERS_HAS_VALUE,
|
||||||
|
FUNCTION_MODIFIER,
|
||||||
|
ENUM_CONSTANTS,
|
||||||
|
BASE_CLASS_COUNT,
|
||||||
|
FIELDS_SIZE,
|
||||||
|
MEMBER_FUNCTION_COUNT,
|
||||||
|
VTABLE_GLOBAL,
|
||||||
|
TYPE_NAME,
|
||||||
|
VARIABLE_CLASS,
|
||||||
|
VARIABLE_TYPE,
|
||||||
|
VARIABLE_STORAGE,
|
||||||
|
VARIABLE_BLOCK
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompareResult {
|
||||||
|
CompareResult(CompareResultType type) : type(type), fail_reason(CompareFailReason::NONE) {}
|
||||||
|
CompareResult(CompareFailReason reason) : type(CompareResultType::DIFFERS), fail_reason(reason) {}
|
||||||
|
CompareResultType type;
|
||||||
|
CompareFailReason fail_reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compare two AST nodes and their children recursively. This will only check
|
||||||
|
// fields that will be equal for two versions of the same type from different
|
||||||
|
// translation units.
|
||||||
|
CompareResult compare_nodes(const Node& lhs, const Node& rhs, const SymbolDatabase* database, bool check_intrusive_fields);
|
||||||
|
|
||||||
|
const char* compare_fail_reason_to_string(CompareFailReason reason);
|
||||||
|
const char* node_type_to_string(const Node& node);
|
||||||
|
const char* storage_class_to_string(StorageClass storage_class);
|
||||||
|
const char* access_specifier_to_string(AccessSpecifier specifier);
|
||||||
|
const char* builtin_class_to_string(BuiltInClass bclass);
|
||||||
|
|
||||||
|
s32 builtin_class_size(BuiltInClass bclass);
|
||||||
|
|
||||||
|
enum TraversalOrder {
|
||||||
|
PREORDER_TRAVERSAL,
|
||||||
|
POSTORDER_TRAVERSAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ExplorationMode {
|
||||||
|
EXPLORE_CHILDREN,
|
||||||
|
DONT_EXPLORE_CHILDREN
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ThisNode, typename Callback>
|
||||||
|
void for_each_node(ThisNode& node, TraversalOrder order, Callback callback)
|
||||||
|
{
|
||||||
|
if(order == PREORDER_TRAVERSAL && callback(node) == DONT_EXPLORE_CHILDREN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch(node.descriptor) {
|
||||||
|
case ARRAY: {
|
||||||
|
auto& array = node.template as<Array>();
|
||||||
|
for_each_node(*array.element_type.get(), order, callback);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BITFIELD: {
|
||||||
|
auto& bitfield = node.template as<BitField>();
|
||||||
|
for_each_node(*bitfield.underlying_type.get(), order, callback);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BUILTIN: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ENUM: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ERROR_NODE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FUNCTION: {
|
||||||
|
auto& func = node.template as<Function>();
|
||||||
|
if(func.return_type.has_value()) {
|
||||||
|
for_each_node(*func.return_type->get(), order, callback);
|
||||||
|
}
|
||||||
|
if(func.parameters.has_value()) {
|
||||||
|
for(auto& child : *func.parameters) {
|
||||||
|
for_each_node(*child.get(), order, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case POINTER_OR_REFERENCE: {
|
||||||
|
auto& pointer_or_reference = node.template as<PointerOrReference>();
|
||||||
|
for_each_node(*pointer_or_reference.value_type.get(), order, callback);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case POINTER_TO_DATA_MEMBER: {
|
||||||
|
auto& pointer = node.template as<PointerToDataMember>();
|
||||||
|
for_each_node(*pointer.class_type.get(), order, callback);
|
||||||
|
for_each_node(*pointer.member_type.get(), order, callback);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STRUCT_OR_UNION: {
|
||||||
|
auto& struct_or_union = node.template as<StructOrUnion>();
|
||||||
|
for(auto& child : struct_or_union.base_classes) {
|
||||||
|
for_each_node(*child.get(), order, callback);
|
||||||
|
}
|
||||||
|
for(auto& child : struct_or_union.fields) {
|
||||||
|
for_each_node(*child.get(), order, callback);
|
||||||
|
}
|
||||||
|
for(auto& child : struct_or_union.member_functions) {
|
||||||
|
for_each_node(*child.get(), order, callback);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TYPE_NAME: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(order == POSTORDER_TRAVERSAL) {
|
||||||
|
callback(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
Result<ElfFile> ElfFile::parse(std::vector<u8> image)
|
||||||
|
{
|
||||||
|
ElfFile elf;
|
||||||
|
elf.image = std::move(image);
|
||||||
|
|
||||||
|
const ElfIdentHeader* ident = get_unaligned<ElfIdentHeader>(elf.image, 0);
|
||||||
|
CCC_CHECK(ident, "ELF ident header out of range.");
|
||||||
|
CCC_CHECK(ident->magic == CCC_FOURCC("\x7f\x45\x4c\x46"), "Not an ELF file.");
|
||||||
|
CCC_CHECK(ident->e_class == ElfIdentClass::B32, "Wrong ELF class (not 32 bit).");
|
||||||
|
|
||||||
|
const ElfFileHeader* header = get_unaligned<ElfFileHeader>(elf.image, sizeof(ElfIdentHeader));
|
||||||
|
CCC_CHECK(header, "ELF file header out of range.");
|
||||||
|
elf.file_header = *header;
|
||||||
|
|
||||||
|
const ElfSectionHeader* shstr_section_header =
|
||||||
|
get_unaligned<ElfSectionHeader>(elf.image, header->shoff + header->shstrndx * sizeof(ElfSectionHeader));
|
||||||
|
CCC_CHECK(shstr_section_header, "ELF section name header out of range.");
|
||||||
|
|
||||||
|
for(u32 i = 0; i < header->shnum; i++) {
|
||||||
|
u64 header_offset = header->shoff + i * sizeof(ElfSectionHeader);
|
||||||
|
const ElfSectionHeader* section_header = get_unaligned<ElfSectionHeader>(elf.image, header_offset);
|
||||||
|
CCC_CHECK(section_header, "ELF section header out of range.");
|
||||||
|
|
||||||
|
std::optional<std::string_view> name = get_string(elf.image, shstr_section_header->offset + section_header->name);
|
||||||
|
CCC_CHECK(name.has_value(), "ELF section name out of range.");
|
||||||
|
|
||||||
|
ElfSection& section = elf.sections.emplace_back();
|
||||||
|
section.name = *name;
|
||||||
|
section.header = *section_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(u32 i = 0; i < header->phnum; i++) {
|
||||||
|
u64 header_offset = header->phoff + i * sizeof(ElfProgramHeader);
|
||||||
|
const ElfProgramHeader* program_header = get_unaligned<ElfProgramHeader>(elf.image, header_offset);
|
||||||
|
CCC_CHECK(program_header, "ELF program header out of range.");
|
||||||
|
|
||||||
|
elf.segments.emplace_back(*program_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elf;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> ElfFile::create_section_symbols(
|
||||||
|
SymbolDatabase& database, const SymbolGroup& group) const
|
||||||
|
{
|
||||||
|
for(const ElfSection& section : sections) {
|
||||||
|
Address address = Address::non_zero(section.header.addr);
|
||||||
|
|
||||||
|
Result<Section*> symbol = database.sections.create_symbol(
|
||||||
|
section.name, address, group.source, group.module_symbol);
|
||||||
|
CCC_RETURN_IF_ERROR(symbol);
|
||||||
|
|
||||||
|
(*symbol)->set_size(section.header.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ElfSection* ElfFile::lookup_section(const char* name) const
|
||||||
|
{
|
||||||
|
for(const ElfSection& section : sections) {
|
||||||
|
if(section.name == name) {
|
||||||
|
return §ion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<u32> ElfFile::file_offset_to_virtual_address(u32 file_offset) const
|
||||||
|
{
|
||||||
|
for(const ElfProgramHeader& segment : segments) {
|
||||||
|
if(file_offset >= segment.offset && file_offset < segment.offset + segment.filesz) {
|
||||||
|
return segment.vaddr + file_offset - segment.offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ElfProgramHeader* ElfFile::entry_point_segment() const
|
||||||
|
{
|
||||||
|
const ccc::ElfProgramHeader* entry_segment = nullptr;
|
||||||
|
for(const ccc::ElfProgramHeader& segment : segments) {
|
||||||
|
if(file_header.entry >= segment.vaddr && file_header.entry < segment.vaddr + segment.filesz) {
|
||||||
|
entry_segment = &segment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entry_segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::span<const u8>> ElfFile::get_virtual(u32 address, u32 size) const
|
||||||
|
{
|
||||||
|
u32 end_address = address + size;
|
||||||
|
|
||||||
|
if(end_address >= address) {
|
||||||
|
for(const ElfProgramHeader& segment : segments) {
|
||||||
|
if(address >= segment.vaddr && end_address <= segment.vaddr + segment.filesz) {
|
||||||
|
size_t begin_offset = segment.offset + (address - segment.vaddr);
|
||||||
|
size_t end_offset = begin_offset + size;
|
||||||
|
if(begin_offset <= image.size() && end_offset <= image.size()) {
|
||||||
|
return std::span<const u8>(image.data() + begin_offset, image.data() + end_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ElfFile::copy_virtual(u8* dest, u32 address, u32 size) const
|
||||||
|
{
|
||||||
|
std::optional<std::span<const u8>> block = get_virtual(address, size);
|
||||||
|
if(!block.has_value()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dest, block->data(), size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "symbol_database.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
enum class ElfIdentClass : u8 {
|
||||||
|
B32 = 0x1,
|
||||||
|
B64 = 0x2
|
||||||
|
};
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(ElfIdentHeader,
|
||||||
|
/* 0x0 */ u32 magic; // 7f 45 4c 46
|
||||||
|
/* 0x4 */ ElfIdentClass e_class;
|
||||||
|
/* 0x5 */ u8 endianess;
|
||||||
|
/* 0x6 */ u8 version;
|
||||||
|
/* 0x7 */ u8 os_abi;
|
||||||
|
/* 0x8 */ u8 abi_version;
|
||||||
|
/* 0x9 */ u8 pad[7];
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class ElfFileType : u16 {
|
||||||
|
NONE = 0x00,
|
||||||
|
REL = 0x01,
|
||||||
|
EXEC = 0x02,
|
||||||
|
DYN = 0x03,
|
||||||
|
CORE = 0x04,
|
||||||
|
LOOS = 0xfe00,
|
||||||
|
HIOS = 0xfeff,
|
||||||
|
LOPROC = 0xff00,
|
||||||
|
HIPROC = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ElfMachine : u16 {
|
||||||
|
MIPS = 0x08
|
||||||
|
};
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(ElfFileHeader,
|
||||||
|
/* 0x10 */ ElfFileType type;
|
||||||
|
/* 0x12 */ ElfMachine machine;
|
||||||
|
/* 0x14 */ u32 version;
|
||||||
|
/* 0x18 */ u32 entry;
|
||||||
|
/* 0x1c */ u32 phoff;
|
||||||
|
/* 0x20 */ u32 shoff;
|
||||||
|
/* 0x24 */ u32 flags;
|
||||||
|
/* 0x28 */ u16 ehsize;
|
||||||
|
/* 0x2a */ u16 phentsize;
|
||||||
|
/* 0x2c */ u16 phnum;
|
||||||
|
/* 0x2e */ u16 shentsize;
|
||||||
|
/* 0x30 */ u16 shnum;
|
||||||
|
/* 0x32 */ u16 shstrndx;
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class ElfSectionType : u32 {
|
||||||
|
NULL_SECTION = 0x0,
|
||||||
|
PROGBITS = 0x1,
|
||||||
|
SYMTAB = 0x2,
|
||||||
|
STRTAB = 0x3,
|
||||||
|
RELA = 0x4,
|
||||||
|
HASH = 0x5,
|
||||||
|
DYNAMIC = 0x6,
|
||||||
|
NOTE = 0x7,
|
||||||
|
NOBITS = 0x8,
|
||||||
|
REL = 0x9,
|
||||||
|
SHLIB = 0xa,
|
||||||
|
DYNSYM = 0xb,
|
||||||
|
INIT_ARRAY = 0xe,
|
||||||
|
FINI_ARRAY = 0xf,
|
||||||
|
PREINIT_ARRAY = 0x10,
|
||||||
|
GROUP = 0x11,
|
||||||
|
SYMTAB_SHNDX = 0x12,
|
||||||
|
NUM = 0x13,
|
||||||
|
LOOS = 0x60000000,
|
||||||
|
MIPS_DEBUG = 0x70000005
|
||||||
|
};
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(ElfSectionHeader,
|
||||||
|
/* 0x00 */ u32 name;
|
||||||
|
/* 0x04 */ ElfSectionType type;
|
||||||
|
/* 0x08 */ u32 flags;
|
||||||
|
/* 0x0c */ u32 addr;
|
||||||
|
/* 0x10 */ u32 offset;
|
||||||
|
/* 0x14 */ u32 size;
|
||||||
|
/* 0x18 */ u32 link;
|
||||||
|
/* 0x1c */ u32 info;
|
||||||
|
/* 0x20 */ u32 addralign;
|
||||||
|
/* 0x24 */ u32 entsize;
|
||||||
|
)
|
||||||
|
|
||||||
|
struct ElfSection {
|
||||||
|
std::string name;
|
||||||
|
ElfSectionHeader header;
|
||||||
|
};
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(ElfProgramHeader,
|
||||||
|
/* 0x00 */ u32 type;
|
||||||
|
/* 0x04 */ u32 offset;
|
||||||
|
/* 0x08 */ u32 vaddr;
|
||||||
|
/* 0x0c */ u32 paddr;
|
||||||
|
/* 0x10 */ u32 filesz;
|
||||||
|
/* 0x14 */ u32 memsz;
|
||||||
|
/* 0x18 */ u32 flags;
|
||||||
|
/* 0x1c */ u32 align;
|
||||||
|
)
|
||||||
|
|
||||||
|
struct ElfFile {
|
||||||
|
ElfFileHeader file_header;
|
||||||
|
std::vector<u8> image;
|
||||||
|
std::vector<ElfSection> sections;
|
||||||
|
std::vector<ElfProgramHeader> segments;
|
||||||
|
|
||||||
|
// Parse the ELF file header, section headers and program headers.
|
||||||
|
static Result<ElfFile> parse(std::vector<u8> image);
|
||||||
|
|
||||||
|
// Create a section object for each section header in the ELF file.
|
||||||
|
Result<void> create_section_symbols(SymbolDatabase& database, const SymbolGroup& group) const;
|
||||||
|
|
||||||
|
const ElfSection* lookup_section(const char* name) const;
|
||||||
|
std::optional<u32> file_offset_to_virtual_address(u32 file_offset) const;
|
||||||
|
|
||||||
|
// Find the program header for the segment that contains the entry point.
|
||||||
|
const ElfProgramHeader* entry_point_segment() const;
|
||||||
|
|
||||||
|
// Retrieve a block of data in an ELF file given its address and size.
|
||||||
|
std::optional<std::span<const u8>> get_virtual(u32 address, u32 size) const;
|
||||||
|
|
||||||
|
// Copy a block of data in an ELF file to the destination buffer given its
|
||||||
|
// address and size.
|
||||||
|
bool copy_virtual(u8* dest, u32 address, u32 size) const;
|
||||||
|
|
||||||
|
// Retrieve an object of type T from an ELF file given its address.
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T> get_object_virtual(u32 address) const
|
||||||
|
{
|
||||||
|
std::optional<std::span<const u8>> result = get_virtual(address, sizeof(T));
|
||||||
|
if(!result.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *(T*) result->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve an array of objects of type T from an ELF file given its
|
||||||
|
// address and element count.
|
||||||
|
template <typename T>
|
||||||
|
std::optional<std::span<const T>> get_array_virtual(u32 address, u32 element_count) const
|
||||||
|
{
|
||||||
|
std::optional<std::span<const u8>> result = get_virtual(address, element_count * sizeof(T));
|
||||||
|
if(!result.has_value()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::span<const T>((T*) result->data(), (T*) (result->data() + result->size()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,214 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "elf_symtab.h"
|
||||||
|
|
||||||
|
#include "importer_flags.h"
|
||||||
|
|
||||||
|
namespace ccc::elf {
|
||||||
|
|
||||||
|
enum class SymbolBind : u8 {
|
||||||
|
LOCAL = 0,
|
||||||
|
GLOBAL = 1,
|
||||||
|
WEAK = 2,
|
||||||
|
NUM = 3,
|
||||||
|
GNU_UNIQUE = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SymbolType : u8 {
|
||||||
|
NOTYPE = 0,
|
||||||
|
OBJECT = 1,
|
||||||
|
FUNC = 2,
|
||||||
|
SECTION = 3,
|
||||||
|
FILE = 4,
|
||||||
|
COMMON = 5,
|
||||||
|
TLS = 6,
|
||||||
|
NUM = 7,
|
||||||
|
GNU_IFUNC = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SymbolVisibility {
|
||||||
|
DEFAULT = 0,
|
||||||
|
INTERNAL = 1,
|
||||||
|
HIDDEN = 2,
|
||||||
|
PROTECTED = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(Symbol,
|
||||||
|
/* 0x0 */ u32 name;
|
||||||
|
/* 0x4 */ u32 value;
|
||||||
|
/* 0x8 */ u32 size;
|
||||||
|
/* 0xc */ u8 info;
|
||||||
|
/* 0xd */ u8 other;
|
||||||
|
/* 0xe */ u16 shndx;
|
||||||
|
|
||||||
|
SymbolType type() const { return (SymbolType) (info & 0xf); }
|
||||||
|
SymbolBind bind() const { return (SymbolBind) (info >> 4); }
|
||||||
|
SymbolVisibility visibility() const { return (SymbolVisibility) (other & 0x3); }
|
||||||
|
)
|
||||||
|
|
||||||
|
static const char* symbol_bind_to_string(SymbolBind bind);
|
||||||
|
static const char* symbol_type_to_string(SymbolType type);
|
||||||
|
static const char* symbol_visibility_to_string(SymbolVisibility visibility);
|
||||||
|
|
||||||
|
Result<void> import_symbols(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
std::span<const u8> symtab,
|
||||||
|
std::span<const u8> strtab,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler)
|
||||||
|
{
|
||||||
|
for(u32 i = 0; i < symtab.size() / sizeof(Symbol); i++) {
|
||||||
|
const Symbol* symbol = get_unaligned<Symbol>(symtab, i * sizeof(Symbol));
|
||||||
|
CCC_ASSERT(symbol);
|
||||||
|
|
||||||
|
Address address;
|
||||||
|
if(symbol->value != 0) {
|
||||||
|
address = symbol->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!address.valid() || symbol->visibility() != SymbolVisibility::DEFAULT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(importer_flags & DONT_DEDUPLICATE_SYMBOLS)) {
|
||||||
|
if(database.functions.first_handle_from_starting_address(address).valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(database.global_variables.first_handle_from_starting_address(address).valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(database.local_variables.first_handle_from_starting_address(address).valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string_view> string_view = get_string(strtab, symbol->name);
|
||||||
|
CCC_CHECK(string_view.has_value(), "Symbol string out of range.");
|
||||||
|
std::string string(*string_view);
|
||||||
|
|
||||||
|
switch(symbol->type()) {
|
||||||
|
case SymbolType::NOTYPE: {
|
||||||
|
Result<Label*> label = database.labels.create_symbol(
|
||||||
|
std::move(string), group.source, group.module_symbol, address, importer_flags, demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(label);
|
||||||
|
|
||||||
|
// These symbols get emitted at the same addresses as functions
|
||||||
|
// and aren't extremely useful, so we want to mark them to
|
||||||
|
// prevent them from possibly being used as function names.
|
||||||
|
(*label)->is_junk =
|
||||||
|
(*label)->name() == "__gnu_compiled_c" ||
|
||||||
|
(*label)->name() == "__gnu_compiled_cplusplus" ||
|
||||||
|
(*label)->name() == "gcc2_compiled.";
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolType::OBJECT: {
|
||||||
|
if(symbol->size != 0) {
|
||||||
|
Result<GlobalVariable*> global_variable = database.global_variables.create_symbol(
|
||||||
|
std::move(string), group.source, group.module_symbol, address, importer_flags, demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(global_variable);
|
||||||
|
|
||||||
|
if(*global_variable) {
|
||||||
|
(*global_variable)->set_size(symbol->size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Result<Label*> label = database.labels.create_symbol(
|
||||||
|
std::move(string), group.source, group.module_symbol, address, importer_flags, demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolType::FUNC: {
|
||||||
|
Result<Function*> function = database.functions.create_symbol(
|
||||||
|
std::move(string), group.source, group.module_symbol, address, importer_flags, demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(function);
|
||||||
|
|
||||||
|
if(*function) {
|
||||||
|
(*function)->set_size(symbol->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolType::FILE: {
|
||||||
|
Result<SourceFile*> source_file = database.source_files.create_symbol(
|
||||||
|
std::move(string), group.source, group.module_symbol);
|
||||||
|
CCC_RETURN_IF_ERROR(source_file);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> print_symbol_table(FILE* out, std::span<const u8> symtab, std::span<const u8> strtab)
|
||||||
|
{
|
||||||
|
fprintf(out, "ELF SYMBOLS:\n");
|
||||||
|
fprintf(out, " Num: Value Size Type Bind Vis Ndx Name\n");
|
||||||
|
|
||||||
|
for(u32 i = 0; i < symtab.size() / sizeof(Symbol); i++) {
|
||||||
|
const Symbol* symbol = get_unaligned<Symbol>(symtab, i * sizeof(Symbol));
|
||||||
|
CCC_ASSERT(symbol);
|
||||||
|
|
||||||
|
const char* type = symbol_type_to_string(symbol->type());
|
||||||
|
const char* bind = symbol_bind_to_string(symbol->bind());
|
||||||
|
const char* visibility = symbol_visibility_to_string(symbol->visibility());
|
||||||
|
|
||||||
|
std::optional<std::string_view> string = get_string(strtab, symbol->name);
|
||||||
|
CCC_CHECK(string.has_value(), "Symbol string out of range.");
|
||||||
|
|
||||||
|
fprintf(out, "%6u: %08x %5u %-7s %-7s %-7s %3u %s\n",
|
||||||
|
i, symbol->value, symbol->size, type, bind, visibility, symbol->shndx, string->data());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* symbol_bind_to_string(SymbolBind bind)
|
||||||
|
{
|
||||||
|
switch(bind) {
|
||||||
|
case SymbolBind::LOCAL: return "LOCAL";
|
||||||
|
case SymbolBind::GLOBAL: return "GLOBAL";
|
||||||
|
case SymbolBind::WEAK: return "WEAK";
|
||||||
|
case SymbolBind::NUM: return "NUM";
|
||||||
|
case SymbolBind::GNU_UNIQUE: return "GNU_UNIQUE";
|
||||||
|
}
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* symbol_type_to_string(SymbolType type)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case SymbolType::NOTYPE: return "NOTYPE";
|
||||||
|
case SymbolType::OBJECT: return "OBJECT";
|
||||||
|
case SymbolType::FUNC: return "FUNC";
|
||||||
|
case SymbolType::SECTION: return "SECTION";
|
||||||
|
case SymbolType::FILE: return "FILE";
|
||||||
|
case SymbolType::COMMON: return "COMMON";
|
||||||
|
case SymbolType::TLS: return "TLS";
|
||||||
|
case SymbolType::NUM: return "NUM";
|
||||||
|
case SymbolType::GNU_IFUNC: return "GNU_IFUNC";
|
||||||
|
}
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* symbol_visibility_to_string(SymbolVisibility visibility)
|
||||||
|
{
|
||||||
|
switch(visibility) {
|
||||||
|
case SymbolVisibility::DEFAULT: return "DEFAULT";
|
||||||
|
case SymbolVisibility::INTERNAL: return "INTERNAL";
|
||||||
|
case SymbolVisibility::HIDDEN: return "HIDDEN";
|
||||||
|
case SymbolVisibility::PROTECTED: return "PROTECTED";
|
||||||
|
}
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "symbol_database.h"
|
||||||
|
|
||||||
|
namespace ccc::elf {
|
||||||
|
|
||||||
|
Result<void> import_symbols(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
std::span<const u8> symtab,
|
||||||
|
std::span<const u8> strtab,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler);
|
||||||
|
|
||||||
|
Result<void> print_symbol_table(FILE* out, std::span<const u8> symtab, std::span<const u8> strtab);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "importer_flags.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
const std::vector<ImporterFlagInfo> IMPORTER_FLAGS = {
|
||||||
|
{DEMANGLE_PARAMETERS, "--demangle-parameters", {
|
||||||
|
"Include parameters in demangled function names."
|
||||||
|
}},
|
||||||
|
{DEMANGLE_RETURN_TYPE, "--demangle-return-type", {
|
||||||
|
"Include return types at the end of demangled",
|
||||||
|
"function names if they're available."
|
||||||
|
}},
|
||||||
|
{DONT_DEDUPLICATE_SYMBOLS, "--dont-deduplicate-symbols", {
|
||||||
|
"Do not deduplicate matching symbols from",
|
||||||
|
"different symbol tables. This options has no",
|
||||||
|
"effect on data types."
|
||||||
|
}},
|
||||||
|
{DONT_DEDUPLICATE_TYPES, "--dont-deduplicate-types", {
|
||||||
|
"Do not deduplicate data types from different",
|
||||||
|
"translation units."
|
||||||
|
}},
|
||||||
|
{DONT_DEMANGLE_NAMES, "--dont-demangle-names", {
|
||||||
|
"Do not demangle function names, global variable",
|
||||||
|
"names, or overloaded operator names."
|
||||||
|
}},
|
||||||
|
{INCLUDE_GENERATED_MEMBER_FUNCTIONS, "--include-generated-functions", {
|
||||||
|
"Output member functions that were likely",
|
||||||
|
"automatically generated by the compiler."
|
||||||
|
}},
|
||||||
|
{NO_ACCESS_SPECIFIERS, "--no-access-specifiers", {
|
||||||
|
"Do not print access specifiers."
|
||||||
|
}},
|
||||||
|
{NO_MEMBER_FUNCTIONS, "--no-member-functions", {
|
||||||
|
"Do not print member functions."
|
||||||
|
}},
|
||||||
|
{NO_OPTIMIZED_OUT_FUNCTIONS, "--no-optimized-out-functions", {
|
||||||
|
"Discard functions that were optimized out."
|
||||||
|
}},
|
||||||
|
{STRICT_PARSING, "--strict", {
|
||||||
|
"Make more types of errors fatal."
|
||||||
|
}},
|
||||||
|
{TYPEDEF_ALL_ENUMS, "--typedef-all-enums", {
|
||||||
|
"Force all emitted C++ enums to be defined using",
|
||||||
|
"a typedef. With STABS, it is not always possible",
|
||||||
|
"to determine if an enum was like this in the",
|
||||||
|
"original source code, so this option should be",
|
||||||
|
"useful for reverse engineering C projects."
|
||||||
|
}},
|
||||||
|
{TYPEDEF_ALL_STRUCTS, "--typedef-all-structs", {
|
||||||
|
"Force all emitted C++ structure types to be",
|
||||||
|
"defined using a typedef."
|
||||||
|
}},
|
||||||
|
{TYPEDEF_ALL_UNIONS, "--typedef-all-unions", {
|
||||||
|
"Force all emitted C++ union types to be defined",
|
||||||
|
"using a typedef."
|
||||||
|
}},
|
||||||
|
{UNIQUE_FUNCTIONS, "--unique-functions", {
|
||||||
|
" If multiple identical .mdebug function symbols",
|
||||||
|
"are present, find the one that seems to have",
|
||||||
|
"actually been included in the linked binary, and",
|
||||||
|
"remove the addresses from all the rest. Using",
|
||||||
|
"this importer flag in combination with",
|
||||||
|
"--no-optimized-out-functions will remove these",
|
||||||
|
"duplicate function symbols entirely."
|
||||||
|
}}
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 parse_importer_flag(const char* argument)
|
||||||
|
{
|
||||||
|
for(const ImporterFlagInfo& flag : IMPORTER_FLAGS) {
|
||||||
|
if(strcmp(flag.argument, argument) == 0) {
|
||||||
|
return flag.flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO_IMPORTER_FLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_importer_flags_help(FILE* out)
|
||||||
|
{
|
||||||
|
for(const ImporterFlagInfo& flag : IMPORTER_FLAGS) {
|
||||||
|
fprintf(out, "\n");
|
||||||
|
fprintf(out, " %-29s ", flag.argument);
|
||||||
|
for(size_t i = 0; i < flag.help_text.size(); i++) {
|
||||||
|
if(i > 0) {
|
||||||
|
fprintf(out, " ");
|
||||||
|
}
|
||||||
|
fprintf(out, "%s\n", flag.help_text[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
enum ImporterFlags {
|
||||||
|
NO_IMPORTER_FLAGS = 0,
|
||||||
|
DEMANGLE_PARAMETERS = (1 << 0),
|
||||||
|
DEMANGLE_RETURN_TYPE = (1 << 1),
|
||||||
|
DONT_DEDUPLICATE_SYMBOLS = (1 << 2),
|
||||||
|
DONT_DEDUPLICATE_TYPES = (1 << 3),
|
||||||
|
DONT_DEMANGLE_NAMES = (1 << 4),
|
||||||
|
INCLUDE_GENERATED_MEMBER_FUNCTIONS = (1 << 5),
|
||||||
|
NO_ACCESS_SPECIFIERS = (1 << 6),
|
||||||
|
NO_MEMBER_FUNCTIONS = (1 << 7),
|
||||||
|
NO_OPTIMIZED_OUT_FUNCTIONS = (1 << 8),
|
||||||
|
STRICT_PARSING = (1 << 9),
|
||||||
|
TYPEDEF_ALL_ENUMS = (1 << 10),
|
||||||
|
TYPEDEF_ALL_STRUCTS = (1 << 11),
|
||||||
|
TYPEDEF_ALL_UNIONS = (1 << 12),
|
||||||
|
UNIQUE_FUNCTIONS = (1 << 13)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImporterFlagInfo {
|
||||||
|
ImporterFlags flag;
|
||||||
|
const char* argument;
|
||||||
|
std::vector<const char*> help_text;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const std::vector<ImporterFlagInfo> IMPORTER_FLAGS;
|
||||||
|
|
||||||
|
u32 parse_importer_flag(const char* argument);
|
||||||
|
void print_importer_flags_help(FILE* out);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,349 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "mdebug_analysis.h"
|
||||||
|
|
||||||
|
#include "stabs_to_ast.h"
|
||||||
|
|
||||||
|
namespace ccc::mdebug {
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::stab_magic(const char* magic)
|
||||||
|
{
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::source_file(const char* path, Address text_address)
|
||||||
|
{
|
||||||
|
if(m_next_relative_path.empty()) {
|
||||||
|
m_next_relative_path = m_source_file.command_line_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::data_type(const ParsedSymbol& symbol)
|
||||||
|
{
|
||||||
|
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(
|
||||||
|
*symbol.name_colon_type.type.get(), nullptr, m_stabs_to_ast_state, 0, false, false);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
|
||||||
|
if(symbol.is_typedef && (*node)->descriptor == ast::STRUCT_OR_UNION) {
|
||||||
|
ast::StructOrUnion& struct_or_union = (*node)->as<ast::StructOrUnion>();
|
||||||
|
const std::string& name = symbol.name_colon_type.name;
|
||||||
|
StabsTypeNumber type_number = symbol.name_colon_type.type->type_number;
|
||||||
|
fix_recursively_emitted_structures(struct_or_union, name, type_number, m_stabs_to_ast_state.file_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_struct = (*node)->descriptor == ast::STRUCT_OR_UNION && (*node)->as<ast::StructOrUnion>().is_struct;
|
||||||
|
bool force_typedef =
|
||||||
|
((m_context.importer_flags & TYPEDEF_ALL_ENUMS) && (*node)->descriptor == ast::ENUM) ||
|
||||||
|
((m_context.importer_flags & TYPEDEF_ALL_STRUCTS) && (*node)->descriptor == ast::STRUCT_OR_UNION && is_struct) ||
|
||||||
|
((m_context.importer_flags & TYPEDEF_ALL_UNIONS) && (*node)->descriptor == ast::STRUCT_OR_UNION && !is_struct);
|
||||||
|
|
||||||
|
(*node)->name = (symbol.name_colon_type.name == " ") ? "" : symbol.name_colon_type.name;
|
||||||
|
if(symbol.is_typedef || force_typedef) {
|
||||||
|
(*node)->storage_class = STORAGE_CLASS_TYPEDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name = (*node)->name.c_str();
|
||||||
|
StabsTypeNumber number = symbol.name_colon_type.type->type_number;
|
||||||
|
|
||||||
|
if(m_context.importer_flags & DONT_DEDUPLICATE_TYPES) {
|
||||||
|
Result<DataType*> data_type = m_database.data_types.create_symbol(
|
||||||
|
name, m_context.group.source, m_context.group.module_symbol);
|
||||||
|
CCC_RETURN_IF_ERROR(data_type);
|
||||||
|
|
||||||
|
m_source_file.stabs_type_number_to_handle[number] = (*data_type)->handle();
|
||||||
|
(*data_type)->set_type(std::move(*node));
|
||||||
|
|
||||||
|
(*data_type)->files = {m_source_file.handle()};
|
||||||
|
} else {
|
||||||
|
Result<ccc::DataType*> type = m_database.create_data_type_if_unique(
|
||||||
|
std::move(*node), number, name, m_source_file, m_context.group);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::global_variable(
|
||||||
|
const char* mangled_name, Address address, const StabsType& type, bool is_static, GlobalStorageLocation location)
|
||||||
|
{
|
||||||
|
Result<GlobalVariable*> global = m_database.global_variables.create_symbol(
|
||||||
|
mangled_name, m_context.group.source, m_context.group.module_symbol, address, m_context.importer_flags, m_context.demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(global);
|
||||||
|
CCC_ASSERT(*global);
|
||||||
|
|
||||||
|
m_global_variables.emplace_back((*global)->handle());
|
||||||
|
|
||||||
|
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(type, nullptr, m_stabs_to_ast_state, 0, true, false);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
|
||||||
|
if(is_static) {
|
||||||
|
(*global)->storage_class = STORAGE_CLASS_STATIC;
|
||||||
|
}
|
||||||
|
(*global)->set_type(std::move(*node));
|
||||||
|
|
||||||
|
(*global)->storage.location = location;
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::sub_source_file(const char* path, Address text_address)
|
||||||
|
{
|
||||||
|
if(m_current_function && m_state == IN_FUNCTION_BEGINNING) {
|
||||||
|
Function::SubSourceFile& sub = m_current_function->sub_source_files.emplace_back();
|
||||||
|
sub.address = text_address;
|
||||||
|
sub.relative_path = path;
|
||||||
|
} else {
|
||||||
|
m_next_relative_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::procedure(
|
||||||
|
const char* mangled_name, Address address, const ProcedureDescriptor* procedure_descriptor, bool is_static)
|
||||||
|
{
|
||||||
|
if(!m_current_function || strcmp(mangled_name, m_current_function->mangled_name().c_str()) != 0) {
|
||||||
|
Result<void> result = create_function(mangled_name, address);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_static) {
|
||||||
|
m_current_function->storage_class = STORAGE_CLASS_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(procedure_descriptor) {
|
||||||
|
m_current_function->stack_frame_size = procedure_descriptor->frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::label(const char* label, Address address, s32 line_number)
|
||||||
|
{
|
||||||
|
if(address.valid() && m_current_function && label[0] == '$') {
|
||||||
|
Function::LineNumberPair& pair = m_current_function->line_numbers.emplace_back();
|
||||||
|
pair.address = address;
|
||||||
|
pair.line_number = line_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::text_end(const char* name, s32 function_size)
|
||||||
|
{
|
||||||
|
if(m_state == IN_FUNCTION_BEGINNING) {
|
||||||
|
CCC_CHECK(m_current_function, "END TEXT symbol outside of function.");
|
||||||
|
m_current_function->set_size(function_size);
|
||||||
|
m_state = IN_FUNCTION_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::function(const char* mangled_name, const StabsType& return_type, Address address)
|
||||||
|
{
|
||||||
|
if(!m_current_function || strcmp(mangled_name, m_current_function->mangled_name().c_str()) != 0) {
|
||||||
|
Result<void> result = create_function(mangled_name, address);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
} else {
|
||||||
|
// For MTV Music Maker 2, the addresses for static functions stored in
|
||||||
|
// the PROC symbols are relative to the translation unit, while the
|
||||||
|
// addresses stored in the FUN symbol are absolute. This is the only
|
||||||
|
// game I've found that seems to have this problem, but since in all
|
||||||
|
// other cases it seems all these addresses are all absolute, I may as
|
||||||
|
// well add in a hack here to deal with it.
|
||||||
|
bool no_module_base_address = m_context.group.module_symbol && m_context.group.module_symbol->address().get_or_zero() == 0;
|
||||||
|
bool new_address_greater = address.valid() && address > m_current_function->address();
|
||||||
|
if(no_module_base_address && new_address_greater) {
|
||||||
|
m_database.functions.move_symbol(m_current_function->handle(), address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(return_type, nullptr, m_stabs_to_ast_state, 0, true, true);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
m_current_function->set_type(std::move(*node));
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::function_end()
|
||||||
|
{
|
||||||
|
if(m_current_function) {
|
||||||
|
m_current_function->set_parameter_variables(std::move(m_current_parameter_variables), m_database);
|
||||||
|
m_current_function->set_local_variables(std::move(m_current_local_variables), m_database);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_current_function = nullptr;
|
||||||
|
m_current_parameter_variables = std::vector<ParameterVariableHandle>();
|
||||||
|
m_current_local_variables = std::vector<LocalVariableHandle>();
|
||||||
|
|
||||||
|
m_blocks.clear();
|
||||||
|
m_pending_local_variables.clear();
|
||||||
|
|
||||||
|
m_state = NOT_IN_FUNCTION;
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::parameter(
|
||||||
|
const char* name, const StabsType& type, bool is_stack, s32 value, bool is_by_reference)
|
||||||
|
{
|
||||||
|
CCC_CHECK(m_current_function, "Parameter symbol before first func/proc symbol.");
|
||||||
|
|
||||||
|
Result<ParameterVariable*> parameter_variable = m_database.parameter_variables.create_symbol(
|
||||||
|
name, m_context.group.source, m_context.group.module_symbol);
|
||||||
|
CCC_RETURN_IF_ERROR(parameter_variable);
|
||||||
|
|
||||||
|
m_current_parameter_variables.emplace_back((*parameter_variable)->handle());
|
||||||
|
|
||||||
|
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(type, nullptr, m_stabs_to_ast_state, 0, true, true);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
(*parameter_variable)->set_type(std::move(*node));
|
||||||
|
|
||||||
|
if(is_stack) {
|
||||||
|
StackStorage& stack_storage = (*parameter_variable)->storage.emplace<StackStorage>();
|
||||||
|
stack_storage.stack_pointer_offset = value;
|
||||||
|
} else {
|
||||||
|
RegisterStorage& register_storage = (*parameter_variable)->storage.emplace<RegisterStorage>();
|
||||||
|
register_storage.dbx_register_number = value;
|
||||||
|
register_storage.is_by_reference = is_by_reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::local_variable(
|
||||||
|
const char* name, const StabsType& type, u32 value, StabsSymbolDescriptor desc, SymbolClass sclass)
|
||||||
|
{
|
||||||
|
if(!m_current_function) {
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Address address = (desc == StabsSymbolDescriptor::STATIC_LOCAL_VARIABLE) ? value : Address();
|
||||||
|
Result<LocalVariable*> local_variable = m_database.local_variables.create_symbol(
|
||||||
|
name, address, m_context.group.source, m_context.group.module_symbol);
|
||||||
|
CCC_RETURN_IF_ERROR(local_variable);
|
||||||
|
|
||||||
|
m_current_local_variables.emplace_back((*local_variable)->handle());
|
||||||
|
m_pending_local_variables.emplace_back((*local_variable)->handle());
|
||||||
|
|
||||||
|
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(type, nullptr, m_stabs_to_ast_state, 0, true, false);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
|
||||||
|
if(desc == StabsSymbolDescriptor::STATIC_LOCAL_VARIABLE) {
|
||||||
|
GlobalStorage& global_storage = (*local_variable)->storage.emplace<GlobalStorage>();
|
||||||
|
std::optional<GlobalStorageLocation> location_opt =
|
||||||
|
symbol_class_to_global_variable_location(sclass);
|
||||||
|
CCC_CHECK(location_opt.has_value(),
|
||||||
|
"Invalid static local variable location %s.",
|
||||||
|
symbol_class(sclass));
|
||||||
|
global_storage.location = *location_opt;
|
||||||
|
(*node)->storage_class = STORAGE_CLASS_STATIC;
|
||||||
|
} else if(desc == StabsSymbolDescriptor::REGISTER_VARIABLE) {
|
||||||
|
RegisterStorage& register_storage = (*local_variable)->storage.emplace<RegisterStorage>();
|
||||||
|
register_storage.dbx_register_number = (s32) value;
|
||||||
|
} else if(desc == StabsSymbolDescriptor::LOCAL_VARIABLE) {
|
||||||
|
StackStorage& stack_storage = (*local_variable)->storage.emplace<StackStorage>();
|
||||||
|
stack_storage.stack_pointer_offset = (s32) value;
|
||||||
|
} else {
|
||||||
|
return CCC_FAILURE("LocalSymbolTableAnalyser::local_variable() called with bad symbol descriptor.");
|
||||||
|
}
|
||||||
|
|
||||||
|
(*local_variable)->set_type(std::move(*node));
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::lbrac(s32 begin_offset)
|
||||||
|
{
|
||||||
|
for(LocalVariableHandle local_variable_handle : m_pending_local_variables) {
|
||||||
|
if(LocalVariable* local_variable = m_database.local_variables.symbol_from_handle(local_variable_handle)) {
|
||||||
|
local_variable->live_range.low = m_source_file.address().value + begin_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blocks.emplace_back(std::move(m_pending_local_variables));
|
||||||
|
m_pending_local_variables = {};
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::rbrac(s32 end_offset)
|
||||||
|
{
|
||||||
|
CCC_CHECK(!m_blocks.empty(), "RBRAC symbol without a matching LBRAC symbol.");
|
||||||
|
|
||||||
|
std::vector<LocalVariableHandle>& variables = m_blocks.back();
|
||||||
|
for(LocalVariableHandle local_variable_handle : variables) {
|
||||||
|
if(LocalVariable* local_variable = m_database.local_variables.symbol_from_handle(local_variable_handle)) {
|
||||||
|
local_variable->live_range.high = m_source_file.address().value + end_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blocks.pop_back();
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::finish()
|
||||||
|
{
|
||||||
|
CCC_CHECK(m_state != IN_FUNCTION_BEGINNING,
|
||||||
|
"Unexpected end of symbol table for '%s'.", m_source_file.name().c_str());
|
||||||
|
|
||||||
|
if(m_current_function) {
|
||||||
|
Result<void> result = function_end();
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_source_file.set_functions(std::move(m_functions), m_database);
|
||||||
|
m_source_file.set_global_variables(std::move(m_global_variables), m_database);
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalSymbolTableAnalyser::create_function(const char* mangled_name, Address address)
|
||||||
|
{
|
||||||
|
if(m_current_function) {
|
||||||
|
Result<void> result = function_end();
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Function*> function = m_database.functions.create_symbol(
|
||||||
|
mangled_name, m_context.group.source, m_context.group.module_symbol, address, m_context.importer_flags, m_context.demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(function);
|
||||||
|
CCC_ASSERT(*function);
|
||||||
|
m_current_function = *function;
|
||||||
|
|
||||||
|
m_functions.emplace_back(m_current_function->handle());
|
||||||
|
|
||||||
|
m_state = IN_FUNCTION_BEGINNING;
|
||||||
|
|
||||||
|
if(!m_next_relative_path.empty() && m_current_function->relative_path != m_source_file.command_line_path) {
|
||||||
|
m_current_function->relative_path = m_next_relative_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<GlobalStorageLocation> symbol_class_to_global_variable_location(SymbolClass symbol_class)
|
||||||
|
{
|
||||||
|
std::optional<GlobalStorageLocation> location;
|
||||||
|
switch(symbol_class) {
|
||||||
|
case SymbolClass::NIL: location = GlobalStorageLocation::NIL; break;
|
||||||
|
case SymbolClass::DATA: location = GlobalStorageLocation::DATA; break;
|
||||||
|
case SymbolClass::BSS: location = GlobalStorageLocation::BSS; break;
|
||||||
|
case SymbolClass::ABS: location = GlobalStorageLocation::ABS; break;
|
||||||
|
case SymbolClass::SDATA: location = GlobalStorageLocation::SDATA; break;
|
||||||
|
case SymbolClass::SBSS: location = GlobalStorageLocation::SBSS; break;
|
||||||
|
case SymbolClass::RDATA: location = GlobalStorageLocation::RDATA; break;
|
||||||
|
case SymbolClass::COMMON: location = GlobalStorageLocation::COMMON; break;
|
||||||
|
case SymbolClass::SCOMMON: location = GlobalStorageLocation::SCOMMON; break;
|
||||||
|
case SymbolClass::SUNDEFINED: location = GlobalStorageLocation::SUNDEFINED; break;
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "importer_flags.h"
|
||||||
|
#include "mdebug_section.h"
|
||||||
|
#include "mdebug_symbols.h"
|
||||||
|
#include "stabs.h"
|
||||||
|
#include "stabs_to_ast.h"
|
||||||
|
#include "symbol_database.h"
|
||||||
|
|
||||||
|
namespace ccc::mdebug {
|
||||||
|
|
||||||
|
struct AnalysisContext {
|
||||||
|
const mdebug::SymbolTableReader* reader = nullptr;
|
||||||
|
const std::map<u32, const mdebug::Symbol*>* external_functions = nullptr;
|
||||||
|
const std::map<std::string, const mdebug::Symbol*>* external_globals = nullptr;
|
||||||
|
SymbolGroup group;
|
||||||
|
u32 importer_flags = NO_IMPORTER_FLAGS;
|
||||||
|
DemanglerFunctions demangler;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LocalSymbolTableAnalyser {
|
||||||
|
public:
|
||||||
|
LocalSymbolTableAnalyser(SymbolDatabase& database, const StabsToAstState& stabs_to_ast_state, const AnalysisContext& context, SourceFile& source_file)
|
||||||
|
: m_database(database)
|
||||||
|
, m_context(context)
|
||||||
|
, m_stabs_to_ast_state(stabs_to_ast_state)
|
||||||
|
, m_source_file(source_file) {}
|
||||||
|
|
||||||
|
// Functions for processing individual symbols.
|
||||||
|
//
|
||||||
|
// In most cases these symbols will appear in the following order:
|
||||||
|
// PROC TEXT
|
||||||
|
// ... line numbers ... ($LM<N>)
|
||||||
|
// END TEXT
|
||||||
|
// LABEL TEXT FUN
|
||||||
|
// ... parameters ...
|
||||||
|
// ... blocks ... (... local variables ... LBRAC ... subblocks ... RBRAC)
|
||||||
|
// NIL NIL FUN
|
||||||
|
//
|
||||||
|
// For some compiler versions the symbols can appear in this order:
|
||||||
|
// LABEL TEXT FUN
|
||||||
|
// ... parameters ...
|
||||||
|
// first line number ($LM1)
|
||||||
|
// PROC TEXT
|
||||||
|
// ... line numbers ... ($LM<N>)
|
||||||
|
// END TEXT
|
||||||
|
// ... blocks ... (... local variables ... LBRAC ... subblocks ... RBRAC)
|
||||||
|
Result<void> stab_magic(const char* magic);
|
||||||
|
Result<void> source_file(const char* path, Address text_address);
|
||||||
|
Result<void> data_type(const ParsedSymbol& symbol);
|
||||||
|
Result<void> global_variable(
|
||||||
|
const char* mangled_name, Address address, const StabsType& type, bool is_static, GlobalStorageLocation location);
|
||||||
|
Result<void> sub_source_file(const char* name, Address text_address);
|
||||||
|
Result<void> procedure(
|
||||||
|
const char* mangled_name, Address address, const ProcedureDescriptor* procedure_descriptor, bool is_static);
|
||||||
|
Result<void> label(const char* label, Address address, s32 line_number);
|
||||||
|
Result<void> text_end(const char* name, s32 function_size);
|
||||||
|
Result<void> function(const char* mangled_name, const StabsType& return_type, Address address);
|
||||||
|
Result<void> function_end();
|
||||||
|
Result<void> parameter(
|
||||||
|
const char* name, const StabsType& type, bool is_stack, s32 value, bool is_by_reference);
|
||||||
|
Result<void> local_variable(
|
||||||
|
const char* name, const StabsType& type, u32 value, StabsSymbolDescriptor desc, SymbolClass sclass);
|
||||||
|
Result<void> lbrac(s32 begin_offset);
|
||||||
|
Result<void> rbrac(s32 end_offset);
|
||||||
|
|
||||||
|
Result<void> finish();
|
||||||
|
|
||||||
|
Result<void> create_function(const char* mangled_name, Address address);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum AnalysisState {
|
||||||
|
NOT_IN_FUNCTION,
|
||||||
|
IN_FUNCTION_BEGINNING,
|
||||||
|
IN_FUNCTION_END
|
||||||
|
};
|
||||||
|
|
||||||
|
SymbolDatabase& m_database;
|
||||||
|
const AnalysisContext& m_context;
|
||||||
|
const StabsToAstState& m_stabs_to_ast_state;
|
||||||
|
|
||||||
|
AnalysisState m_state = NOT_IN_FUNCTION;
|
||||||
|
SourceFile& m_source_file;
|
||||||
|
std::vector<FunctionHandle> m_functions;
|
||||||
|
std::vector<GlobalVariableHandle> m_global_variables;
|
||||||
|
Function* m_current_function = nullptr;
|
||||||
|
std::vector<ParameterVariableHandle> m_current_parameter_variables;
|
||||||
|
std::vector<LocalVariableHandle> m_current_local_variables;
|
||||||
|
std::vector<std::vector<LocalVariableHandle>> m_blocks;
|
||||||
|
std::vector<LocalVariableHandle> m_pending_local_variables;
|
||||||
|
std::string m_next_relative_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<GlobalStorageLocation> symbol_class_to_global_variable_location(SymbolClass symbol_class);
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,668 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "mdebug_importer.h"
|
||||||
|
|
||||||
|
namespace ccc::mdebug {
|
||||||
|
|
||||||
|
static Result<void> resolve_type_names(
|
||||||
|
SymbolDatabase& database, const SymbolGroup& group, u32 importer_flags);
|
||||||
|
static Result<void> resolve_type_name(
|
||||||
|
ast::TypeName& type_name,
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags);
|
||||||
|
static void compute_size_bytes(ast::Node& node, SymbolDatabase& database);
|
||||||
|
static void detect_duplicate_functions(SymbolDatabase& database, const SymbolGroup& group);
|
||||||
|
static void detect_fake_functions(SymbolDatabase& database, const std::map<u32, const mdebug::Symbol*>& external_functions, const SymbolGroup& group);
|
||||||
|
static void destroy_optimized_out_functions(
|
||||||
|
SymbolDatabase& database, const SymbolGroup& group);
|
||||||
|
|
||||||
|
Result<void> import_symbol_table(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
std::span<const u8> elf,
|
||||||
|
s32 section_offset,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
const DemanglerFunctions& demangler,
|
||||||
|
const std::atomic_bool* interrupt)
|
||||||
|
{
|
||||||
|
SymbolTableReader reader;
|
||||||
|
|
||||||
|
Result<void> reader_result = reader.init(elf, section_offset);
|
||||||
|
CCC_RETURN_IF_ERROR(reader_result);
|
||||||
|
|
||||||
|
Result<std::vector<mdebug::Symbol>> external_symbols = reader.parse_external_symbols();
|
||||||
|
CCC_RETURN_IF_ERROR(external_symbols);
|
||||||
|
|
||||||
|
// The addresses of the global variables aren't present in the local symbol
|
||||||
|
// table, so here we extract them from the external table. In addition, for
|
||||||
|
// some games we need to cross reference the function symbols in the local
|
||||||
|
// symbol table with the entries in the external symbol table.
|
||||||
|
std::map<u32, const mdebug::Symbol*> external_functions;
|
||||||
|
std::map<std::string, const mdebug::Symbol*> external_globals;
|
||||||
|
for(const mdebug::Symbol& external : *external_symbols) {
|
||||||
|
if(external.symbol_type == mdebug::SymbolType::PROC) {
|
||||||
|
external_functions[external.value] = &external;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(external.symbol_type == mdebug::SymbolType::GLOBAL
|
||||||
|
&& (external.symbol_class != mdebug::SymbolClass::UNDEFINED)) {
|
||||||
|
external_globals[external.string] = &external;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bundle together some unchanging state to pass to import_files.
|
||||||
|
AnalysisContext context;
|
||||||
|
context.reader = &reader;
|
||||||
|
context.external_functions = &external_functions;
|
||||||
|
context.external_globals = &external_globals;
|
||||||
|
context.group = group;
|
||||||
|
context.importer_flags = importer_flags;
|
||||||
|
context.demangler = demangler;
|
||||||
|
|
||||||
|
Result<void> result = import_files(database, context, interrupt);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> import_files(SymbolDatabase& database, const AnalysisContext& context, const std::atomic_bool* interrupt)
|
||||||
|
{
|
||||||
|
Result<s32> file_count = context.reader->file_count();
|
||||||
|
CCC_RETURN_IF_ERROR(file_count);
|
||||||
|
|
||||||
|
for(s32 i = 0; i < *file_count; i++) {
|
||||||
|
if(interrupt && *interrupt) {
|
||||||
|
return CCC_FAILURE("Operation interrupted by user.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<mdebug::File> file = context.reader->parse_file(i);
|
||||||
|
CCC_RETURN_IF_ERROR(file);
|
||||||
|
|
||||||
|
Result<void> result = import_file(database, *file, context);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The files field may be modified by further analysis passes, so we
|
||||||
|
// need to save this information here.
|
||||||
|
for(DataType& data_type : database.data_types) {
|
||||||
|
if(context.group.is_in_group(data_type) && data_type.files.size() == 1) {
|
||||||
|
data_type.only_defined_in_single_translation_unit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup data types and store data type handles in type names.
|
||||||
|
Result<void> type_name_result = resolve_type_names(database, context.group, context.importer_flags);
|
||||||
|
CCC_RETURN_IF_ERROR(type_name_result);
|
||||||
|
|
||||||
|
// Compute the size in bytes of all the AST nodes.
|
||||||
|
database.for_each_symbol([&](ccc::Symbol& symbol) {
|
||||||
|
if(context.group.is_in_group(symbol) && symbol.type()) {
|
||||||
|
compute_size_bytes(*symbol.type(), database);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Propagate the size information to the global variable symbols.
|
||||||
|
for(GlobalVariable& global_variable : database.global_variables) {
|
||||||
|
if(global_variable.type() && global_variable.type()->size_bytes > -1) {
|
||||||
|
global_variable.set_size((u32) global_variable.type()->size_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate the size information to the static local variable symbols.
|
||||||
|
for(LocalVariable& local_variable : database.local_variables) {
|
||||||
|
bool is_static_local = std::holds_alternative<GlobalStorage>(local_variable.storage);
|
||||||
|
if(is_static_local && local_variable.type() && local_variable.type()->size_bytes > -1) {
|
||||||
|
local_variable.set_size((u32) local_variable.type()->size_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some games (e.g. Jet X2O) have multiple function symbols across different
|
||||||
|
// translation units with the same name and address.
|
||||||
|
if(context.importer_flags & UNIQUE_FUNCTIONS) {
|
||||||
|
detect_duplicate_functions(database, context.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If multiple functions appear at the same address, discard the addresses
|
||||||
|
// of all of them except the real one.
|
||||||
|
if(context.external_functions) {
|
||||||
|
detect_fake_functions(database, *context.external_functions, context.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove functions with no address. If there are any such functions, this
|
||||||
|
// will invalidate all pointers to symbols.
|
||||||
|
if(context.importer_flags & NO_OPTIMIZED_OUT_FUNCTIONS) {
|
||||||
|
destroy_optimized_out_functions(database, context.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> import_file(SymbolDatabase& database, const mdebug::File& input, const AnalysisContext& context)
|
||||||
|
{
|
||||||
|
// Parse the stab strings into a data structure that's vaguely
|
||||||
|
// one-to-one with the text-based representation.
|
||||||
|
u32 importer_flags_for_this_file = context.importer_flags;
|
||||||
|
Result<std::vector<ParsedSymbol>> symbols = parse_symbols(input.symbols, importer_flags_for_this_file);
|
||||||
|
CCC_RETURN_IF_ERROR(symbols);
|
||||||
|
|
||||||
|
// In stabs, types can be referenced by their number from other stabs,
|
||||||
|
// so here we build a map of type numbers to the parsed types.
|
||||||
|
std::map<StabsTypeNumber, const StabsType*> stabs_types;
|
||||||
|
for(const ParsedSymbol& symbol : *symbols) {
|
||||||
|
if(symbol.type == ParsedSymbolType::NAME_COLON_TYPE) {
|
||||||
|
symbol.name_colon_type.type->enumerate_numbered_types(stabs_types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SourceFile*> source_file = database.source_files.create_symbol(
|
||||||
|
input.full_path, input.address, context.group.source, context.group.module_symbol);
|
||||||
|
CCC_RETURN_IF_ERROR(source_file);
|
||||||
|
|
||||||
|
(*source_file)->working_dir = input.working_dir;
|
||||||
|
(*source_file)->command_line_path = input.command_line_path;
|
||||||
|
|
||||||
|
// Sometimes the INFO symbols contain information about what toolchain
|
||||||
|
// version was used for building the executable.
|
||||||
|
for(const mdebug::Symbol& symbol : input.symbols) {
|
||||||
|
if(symbol.symbol_class == mdebug::SymbolClass::INFO && strcmp(symbol.string, "@stabs") != 0) {
|
||||||
|
(*source_file)->toolchain_version_info.emplace(symbol.string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StabsToAstState stabs_to_ast_state;
|
||||||
|
stabs_to_ast_state.file_handle = (*source_file)->handle().value;
|
||||||
|
stabs_to_ast_state.stabs_types = &stabs_types;
|
||||||
|
stabs_to_ast_state.importer_flags = importer_flags_for_this_file;
|
||||||
|
stabs_to_ast_state.demangler = context.demangler;
|
||||||
|
|
||||||
|
// Convert the parsed stabs symbols to a more standard C AST.
|
||||||
|
LocalSymbolTableAnalyser analyser(database, stabs_to_ast_state, context, **source_file);
|
||||||
|
for(const ParsedSymbol& symbol : *symbols) {
|
||||||
|
if(symbol.duplicate) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(symbol.type) {
|
||||||
|
case ParsedSymbolType::NAME_COLON_TYPE: {
|
||||||
|
switch(symbol.name_colon_type.descriptor) {
|
||||||
|
case StabsSymbolDescriptor::LOCAL_FUNCTION:
|
||||||
|
case StabsSymbolDescriptor::GLOBAL_FUNCTION: {
|
||||||
|
const char* name = symbol.name_colon_type.name.c_str();
|
||||||
|
const StabsType& type = *symbol.name_colon_type.type.get();
|
||||||
|
Result<void> result = analyser.function(name, type, symbol.raw->value);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsSymbolDescriptor::REFERENCE_PARAMETER_A:
|
||||||
|
case StabsSymbolDescriptor::REGISTER_PARAMETER:
|
||||||
|
case StabsSymbolDescriptor::VALUE_PARAMETER:
|
||||||
|
case StabsSymbolDescriptor::REFERENCE_PARAMETER_V: {
|
||||||
|
const char* name = symbol.name_colon_type.name.c_str();
|
||||||
|
const StabsType& type = *symbol.name_colon_type.type.get();
|
||||||
|
bool is_stack_variable = symbol.name_colon_type.descriptor == StabsSymbolDescriptor::VALUE_PARAMETER;
|
||||||
|
bool is_by_reference = symbol.name_colon_type.descriptor == StabsSymbolDescriptor::REFERENCE_PARAMETER_A
|
||||||
|
|| symbol.name_colon_type.descriptor == StabsSymbolDescriptor::REFERENCE_PARAMETER_V;
|
||||||
|
|
||||||
|
Result<void> result = analyser.parameter(name, type, is_stack_variable, symbol.raw->value, is_by_reference);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsSymbolDescriptor::REGISTER_VARIABLE:
|
||||||
|
case StabsSymbolDescriptor::LOCAL_VARIABLE:
|
||||||
|
case StabsSymbolDescriptor::STATIC_LOCAL_VARIABLE: {
|
||||||
|
const char* name = symbol.name_colon_type.name.c_str();
|
||||||
|
const StabsType& type = *symbol.name_colon_type.type.get();
|
||||||
|
Result<void> result = analyser.local_variable(
|
||||||
|
name, type, symbol.raw->value, symbol.name_colon_type.descriptor, symbol.raw->symbol_class);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsSymbolDescriptor::GLOBAL_VARIABLE:
|
||||||
|
case StabsSymbolDescriptor::STATIC_GLOBAL_VARIABLE: {
|
||||||
|
const char* name = symbol.name_colon_type.name.c_str();
|
||||||
|
u32 address = -1;
|
||||||
|
std::optional<GlobalStorageLocation> location =
|
||||||
|
symbol_class_to_global_variable_location(symbol.raw->symbol_class);
|
||||||
|
if(symbol.name_colon_type.descriptor == StabsSymbolDescriptor::GLOBAL_VARIABLE) {
|
||||||
|
// The address for non-static global variables is
|
||||||
|
// only stored in the external symbol table (and
|
||||||
|
// the ELF symbol table), so we pull that
|
||||||
|
// information in here.
|
||||||
|
if(context.external_globals) {
|
||||||
|
auto global_symbol = context.external_globals->find(symbol.name_colon_type.name);
|
||||||
|
if(global_symbol != context.external_globals->end()) {
|
||||||
|
address = (u32) global_symbol->second->value;
|
||||||
|
location = symbol_class_to_global_variable_location(global_symbol->second->symbol_class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// And for static global variables it's just stored
|
||||||
|
// in the local symbol table.
|
||||||
|
address = (u32) symbol.raw->value;
|
||||||
|
}
|
||||||
|
CCC_CHECK(location.has_value(), "Invalid global variable location.")
|
||||||
|
const StabsType& type = *symbol.name_colon_type.type.get();
|
||||||
|
bool is_static = symbol.name_colon_type.descriptor == StabsSymbolDescriptor::STATIC_GLOBAL_VARIABLE;
|
||||||
|
Result<void> result = analyser.global_variable(name, address, type, is_static, *location);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsSymbolDescriptor::TYPE_NAME:
|
||||||
|
case StabsSymbolDescriptor::ENUM_STRUCT_OR_TYPE_TAG: {
|
||||||
|
Result<void> result = analyser.data_type(symbol);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ParsedSymbolType::SOURCE_FILE: {
|
||||||
|
Result<void> result = analyser.source_file(symbol.raw->string, symbol.raw->value);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ParsedSymbolType::SUB_SOURCE_FILE: {
|
||||||
|
Result<void> result = analyser.sub_source_file(symbol.raw->string, symbol.raw->value);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ParsedSymbolType::LBRAC: {
|
||||||
|
Result<void> result = analyser.lbrac(symbol.raw->value);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ParsedSymbolType::RBRAC: {
|
||||||
|
Result<void> result = analyser.rbrac(symbol.raw->value);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ParsedSymbolType::FUNCTION_END: {
|
||||||
|
Result<void> result = analyser.function_end();
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ParsedSymbolType::NON_STABS: {
|
||||||
|
if(symbol.raw->symbol_class == mdebug::SymbolClass::TEXT) {
|
||||||
|
if(symbol.raw->symbol_type == mdebug::SymbolType::PROC) {
|
||||||
|
Result<void> result = analyser.procedure(symbol.raw->string, symbol.raw->value, symbol.raw->procedure_descriptor, false);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
} else if(symbol.raw->symbol_type == mdebug::SymbolType::STATICPROC) {
|
||||||
|
Result<void> result = analyser.procedure(symbol.raw->string, symbol.raw->value, symbol.raw->procedure_descriptor, true);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
} else if(symbol.raw->symbol_type == mdebug::SymbolType::LABEL) {
|
||||||
|
Result<void> result = analyser.label(symbol.raw->string, symbol.raw->value, symbol.raw->index);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
} else if(symbol.raw->symbol_type == mdebug::SymbolType::END) {
|
||||||
|
Result<void> result = analyser.text_end(symbol.raw->string, symbol.raw->value);
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> result = analyser.finish();
|
||||||
|
CCC_RETURN_IF_ERROR(result);
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<void> resolve_type_names(
|
||||||
|
SymbolDatabase& database, const SymbolGroup& group, u32 importer_flags)
|
||||||
|
{
|
||||||
|
Result<void> result;
|
||||||
|
database.for_each_symbol([&](ccc::Symbol& symbol) {
|
||||||
|
if(group.is_in_group(symbol) && symbol.type()) {
|
||||||
|
ast::for_each_node(*symbol.type(), ast::PREORDER_TRAVERSAL, [&](ast::Node& node) {
|
||||||
|
if(node.descriptor == ast::TYPE_NAME) {
|
||||||
|
Result<void> type_name_result = resolve_type_name(node.as<ast::TypeName>(), database, group, importer_flags);
|
||||||
|
if(!type_name_result.success()) {
|
||||||
|
result = std::move(type_name_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ast::EXPLORE_CHILDREN;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<void> resolve_type_name(
|
||||||
|
ast::TypeName& type_name,
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags)
|
||||||
|
{
|
||||||
|
ast::TypeName::UnresolvedStabs* unresolved_stabs = type_name.unresolved_stabs.get();
|
||||||
|
if(!unresolved_stabs) {
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup the type by its STABS type number. This path ensures that the
|
||||||
|
// correct type is found even if multiple types have the same name.
|
||||||
|
if(unresolved_stabs->referenced_file_handle != (u32) -1 && unresolved_stabs->stabs_type_number.valid()) {
|
||||||
|
const SourceFile* source_file = database.source_files.symbol_from_handle(unresolved_stabs->referenced_file_handle);
|
||||||
|
CCC_ASSERT(source_file);
|
||||||
|
auto handle = source_file->stabs_type_number_to_handle.find(unresolved_stabs->stabs_type_number);
|
||||||
|
if(handle != source_file->stabs_type_number_to_handle.end()) {
|
||||||
|
type_name.data_type_handle = handle->second.value;
|
||||||
|
type_name.is_forward_declared = false;
|
||||||
|
type_name.unresolved_stabs.reset();
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looking up the type by its STABS type number failed, so look for it by
|
||||||
|
// its name instead. This happens when a type is forward declared but not
|
||||||
|
// defined in a given translation unit.
|
||||||
|
if(!unresolved_stabs->type_name.empty()) {
|
||||||
|
for(auto& name_handle : database.data_types.handles_from_name(unresolved_stabs->type_name)) {
|
||||||
|
DataType* data_type = database.data_types.symbol_from_handle(name_handle.second);
|
||||||
|
if(data_type && group.is_in_group(*data_type)) {
|
||||||
|
type_name.data_type_handle = name_handle.second.value;
|
||||||
|
type_name.is_forward_declared = true;
|
||||||
|
type_name.unresolved_stabs.reset();
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this branch is taken it means the type name was probably from an
|
||||||
|
// automatically generated member function of a nested struct trying to
|
||||||
|
// reference the struct (for the this parameter). We shouldn't create a
|
||||||
|
// forward declared type in this case.
|
||||||
|
if(type_name.source == ast::TypeNameSource::UNNAMED_THIS) {
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type lookup failed. This happens when a type is forward declared in a
|
||||||
|
// translation unit with symbols but is not defined in one. We haven't
|
||||||
|
// already created a forward declared type, so we create one now.
|
||||||
|
std::unique_ptr<ast::Node> forward_declared_node;
|
||||||
|
if(unresolved_stabs->type.has_value()) {
|
||||||
|
switch(*unresolved_stabs->type) {
|
||||||
|
case ast::ForwardDeclaredType::STRUCT: {
|
||||||
|
std::unique_ptr<ast::StructOrUnion> node = std::make_unique<ast::StructOrUnion>();
|
||||||
|
node->is_struct = true;
|
||||||
|
forward_declared_node = std::move(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::ForwardDeclaredType::UNION: {
|
||||||
|
std::unique_ptr<ast::StructOrUnion> node = std::make_unique<ast::StructOrUnion>();
|
||||||
|
node->is_struct = false;
|
||||||
|
forward_declared_node = std::move(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::ForwardDeclaredType::ENUM: {
|
||||||
|
std::unique_ptr<ast::Enum> node = std::make_unique<ast::Enum>();
|
||||||
|
forward_declared_node = std::move(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(forward_declared_node) {
|
||||||
|
Result<DataType*> forward_declared_type = database.data_types.create_symbol(
|
||||||
|
unresolved_stabs->type_name, group.source, group.module_symbol);
|
||||||
|
CCC_RETURN_IF_ERROR(forward_declared_type);
|
||||||
|
|
||||||
|
(*forward_declared_type)->set_type(std::move(forward_declared_node));
|
||||||
|
(*forward_declared_type)->not_defined_in_any_translation_unit = true;
|
||||||
|
|
||||||
|
type_name.data_type_handle = (*forward_declared_type)->handle().value;
|
||||||
|
type_name.is_forward_declared = true;
|
||||||
|
type_name.unresolved_stabs.reset();
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* error_message = "Unresolved %s type name '%s' with STABS type number (%d,%d).";
|
||||||
|
if(importer_flags & STRICT_PARSING) {
|
||||||
|
return CCC_FAILURE(error_message,
|
||||||
|
ast::type_name_source_to_string(type_name.source),
|
||||||
|
type_name.unresolved_stabs->type_name.c_str(),
|
||||||
|
type_name.unresolved_stabs->stabs_type_number.file,
|
||||||
|
type_name.unresolved_stabs->stabs_type_number.type);
|
||||||
|
} else {
|
||||||
|
CCC_WARN(error_message,
|
||||||
|
ast::type_name_source_to_string(type_name.source),
|
||||||
|
type_name.unresolved_stabs->type_name.c_str(),
|
||||||
|
type_name.unresolved_stabs->stabs_type_number.file,
|
||||||
|
type_name.unresolved_stabs->stabs_type_number.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compute_size_bytes(ast::Node& node, SymbolDatabase& database)
|
||||||
|
{
|
||||||
|
for_each_node(node, ast::POSTORDER_TRAVERSAL, [&](ast::Node& node) {
|
||||||
|
// Skip nodes that have already been processed.
|
||||||
|
if(node.size_bytes > -1 || node.cannot_compute_size) {
|
||||||
|
return ast::EXPLORE_CHILDREN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't compute size recursively.
|
||||||
|
node.cannot_compute_size = true;
|
||||||
|
|
||||||
|
switch(node.descriptor) {
|
||||||
|
case ast::ARRAY: {
|
||||||
|
ast::Array& array = node.as<ast::Array>();
|
||||||
|
if(array.element_type->size_bytes > -1) {
|
||||||
|
array.size_bytes = array.element_type->size_bytes * array.element_count;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::BITFIELD: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::BUILTIN: {
|
||||||
|
ast::BuiltIn& built_in = node.as<ast::BuiltIn>();
|
||||||
|
built_in.size_bytes = builtin_class_size(built_in.bclass);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::FUNCTION: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::ENUM: {
|
||||||
|
node.size_bytes = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::ERROR_NODE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::STRUCT_OR_UNION: {
|
||||||
|
node.size_bytes = node.size_bits / 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::POINTER_OR_REFERENCE: {
|
||||||
|
node.size_bytes = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::POINTER_TO_DATA_MEMBER: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::TYPE_NAME: {
|
||||||
|
ast::TypeName& type_name = node.as<ast::TypeName>();
|
||||||
|
DataType* resolved_type = database.data_types.symbol_from_handle(type_name.data_type_handle_unless_forward_declared());
|
||||||
|
if(resolved_type) {
|
||||||
|
ast::Node* resolved_node = resolved_type->type();
|
||||||
|
CCC_ASSERT(resolved_node);
|
||||||
|
if(resolved_node->size_bytes < 0 && !resolved_node->cannot_compute_size) {
|
||||||
|
compute_size_bytes(*resolved_node, database);
|
||||||
|
}
|
||||||
|
type_name.size_bytes = resolved_node->size_bytes;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.size_bytes > -1) {
|
||||||
|
node.cannot_compute_size = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast::EXPLORE_CHILDREN;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void detect_duplicate_functions(SymbolDatabase& database, const SymbolGroup& group)
|
||||||
|
{
|
||||||
|
std::vector<FunctionHandle> duplicate_functions;
|
||||||
|
|
||||||
|
for(Function& test_function : database.functions) {
|
||||||
|
if(!test_function.address().valid() && !group.is_in_group(test_function)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find cases where there are two or more functions at the same address.
|
||||||
|
auto functions_with_same_address = database.functions.handles_from_starting_address(test_function.address());
|
||||||
|
if(functions_with_same_address.begin() == functions_with_same_address.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(++functions_with_same_address.begin() == functions_with_same_address.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to figure out the address of the translation unit which the
|
||||||
|
// version of the function that actually ended up in the linked binary
|
||||||
|
// comes from. We can't just check which source file the symbol comes
|
||||||
|
// from because it may be present in multiple.
|
||||||
|
u32 source_file_address = UINT32_MAX;
|
||||||
|
for(SourceFile& source_file : database.source_files) {
|
||||||
|
if(source_file.address() < test_function.address()) {
|
||||||
|
source_file_address = std::min(source_file.address().value, source_file_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(source_file_address == UINT32_MAX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the addresses from all the matching symbols from other
|
||||||
|
// translation units.
|
||||||
|
FunctionHandle best_handle;
|
||||||
|
u32 best_offset = UINT32_MAX;
|
||||||
|
for(const auto& [address, handle] : functions_with_same_address) {
|
||||||
|
ccc::Function* function = database.functions.symbol_from_handle(handle);
|
||||||
|
if(!function || !group.is_in_group(*function) || function->mangled_name() != test_function.mangled_name()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(address - source_file_address < best_offset) {
|
||||||
|
if(best_handle.valid()) {
|
||||||
|
duplicate_functions.emplace_back(best_handle);
|
||||||
|
}
|
||||||
|
best_handle = function->handle();
|
||||||
|
best_offset = address - source_file_address;
|
||||||
|
} else {
|
||||||
|
duplicate_functions.emplace_back(function->handle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(FunctionHandle duplicate_function : duplicate_functions) {
|
||||||
|
database.functions.move_symbol(duplicate_function, Address());
|
||||||
|
}
|
||||||
|
duplicate_functions.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void detect_fake_functions(SymbolDatabase& database, const std::map<u32, const mdebug::Symbol*>& external_functions, const SymbolGroup& group)
|
||||||
|
{
|
||||||
|
// Find cases where multiple fake function symbols were emitted for a given
|
||||||
|
// address and cross-reference with the external symbol table to try and
|
||||||
|
// find which one is the real one.
|
||||||
|
s32 fake_function_count = 0;
|
||||||
|
for(Function& function : database.functions) {
|
||||||
|
if(!function.address().valid() || !group.is_in_group(function)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find cases where there are two or more functions at the same address.
|
||||||
|
auto functions_with_same_address = database.functions.handles_from_starting_address(function.address());
|
||||||
|
if(functions_with_same_address.begin() == functions_with_same_address.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(++functions_with_same_address.begin() == functions_with_same_address.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto external_function = external_functions.find(function.address().value);
|
||||||
|
if(external_function == external_functions.end() || strcmp(function.mangled_name().c_str(), external_function->second->string) != 0) {
|
||||||
|
database.functions.move_symbol(function.handle(), Address());
|
||||||
|
|
||||||
|
if(fake_function_count < 10) {
|
||||||
|
CCC_WARN("Discarding address of function symbol '%s' as it is probably incorrect.", function.mangled_name().c_str());
|
||||||
|
} else if(fake_function_count == 10) {
|
||||||
|
CCC_WARN("Discarding more addresses of function symbols.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fake_function_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_optimized_out_functions(
|
||||||
|
SymbolDatabase& database, const SymbolGroup& group)
|
||||||
|
{
|
||||||
|
bool marked = false;
|
||||||
|
|
||||||
|
for(Function& function : database.functions) {
|
||||||
|
if(group.is_in_group(function) && !function.address().valid()) {
|
||||||
|
function.mark_for_destruction();
|
||||||
|
marked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(marked) {
|
||||||
|
// This will invalidate all pointers to symbols in the database.
|
||||||
|
database.destroy_marked_symbols();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_in_pointers_to_member_function_definitions(SymbolDatabase& database)
|
||||||
|
{
|
||||||
|
// Fill in pointers from member function declaration to corresponding definitions.
|
||||||
|
for(Function& function : database.functions) {
|
||||||
|
const std::string& qualified_name = function.name();
|
||||||
|
std::string::size_type name_separator_pos = qualified_name.find_last_of("::");
|
||||||
|
if(name_separator_pos == std::string::npos || name_separator_pos < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string function_name = qualified_name.substr(name_separator_pos + 1);
|
||||||
|
|
||||||
|
// This won't work for some template types.
|
||||||
|
std::string::size_type type_separator_pos = qualified_name.find_last_of("::", name_separator_pos - 2);
|
||||||
|
std::string type_name;
|
||||||
|
if(type_separator_pos != std::string::npos) {
|
||||||
|
type_name = qualified_name.substr(type_separator_pos + 1, name_separator_pos - type_separator_pos - 2);
|
||||||
|
} else {
|
||||||
|
type_name = qualified_name.substr(0, name_separator_pos - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& name_handle : database.data_types.handles_from_name(type_name)) {
|
||||||
|
DataType* data_type = database.data_types.symbol_from_handle(name_handle.second);
|
||||||
|
if(!data_type || !data_type->type() || data_type->type()->descriptor != ast::STRUCT_OR_UNION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::StructOrUnion& struct_or_union = data_type->type()->as<ast::StructOrUnion>();
|
||||||
|
for(std::unique_ptr<ast::Node>& declaration : struct_or_union.member_functions) {
|
||||||
|
if(declaration->name == function_name) {
|
||||||
|
declaration->as<ast::Function>().definition_handle = function.handle().value;
|
||||||
|
function.is_member_function_ish = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(function.is_member_function_ish) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "mdebug_analysis.h"
|
||||||
|
#include "mdebug_section.h"
|
||||||
|
#include "symbol_database.h"
|
||||||
|
|
||||||
|
namespace ccc::mdebug {
|
||||||
|
|
||||||
|
// Perform all the main analysis passes on the mdebug symbol table and convert
|
||||||
|
// it to a set of C++ ASTs.
|
||||||
|
Result<void> import_symbol_table(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
std::span<const u8> elf,
|
||||||
|
s32 section_offset,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
const DemanglerFunctions& demangler,
|
||||||
|
const std::atomic_bool* interrupt);
|
||||||
|
Result<void> import_files(SymbolDatabase& database, const AnalysisContext& context, const std::atomic_bool* interrupt);
|
||||||
|
Result<void> import_file(SymbolDatabase& database, const mdebug::File& input, const AnalysisContext& context);
|
||||||
|
|
||||||
|
// Try to add pointers from member function declarations to their definitions
|
||||||
|
// using a heuristic.
|
||||||
|
void fill_in_pointers_to_member_function_definitions(SymbolDatabase& database);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,474 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "mdebug_section.h"
|
||||||
|
|
||||||
|
namespace ccc::mdebug {
|
||||||
|
|
||||||
|
// MIPS debug symbol table headers.
|
||||||
|
// See include/coff/sym.h from GNU binutils for more information.
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(SymbolicHeader,
|
||||||
|
/* 0x00 */ s16 magic;
|
||||||
|
/* 0x02 */ s16 version_stamp;
|
||||||
|
/* 0x04 */ s32 line_number_count;
|
||||||
|
/* 0x08 */ s32 line_numbers_size_bytes;
|
||||||
|
/* 0x0c */ s32 line_numbers_offset;
|
||||||
|
/* 0x10 */ s32 dense_numbers_count;
|
||||||
|
/* 0x14 */ s32 dense_numbers_offset;
|
||||||
|
/* 0x18 */ s32 procedure_descriptor_count;
|
||||||
|
/* 0x1c */ s32 procedure_descriptors_offset;
|
||||||
|
/* 0x20 */ s32 local_symbol_count;
|
||||||
|
/* 0x24 */ s32 local_symbols_offset;
|
||||||
|
/* 0x28 */ s32 optimization_symbols_count;
|
||||||
|
/* 0x2c */ s32 optimization_symbols_offset;
|
||||||
|
/* 0x30 */ s32 auxiliary_symbol_count;
|
||||||
|
/* 0x34 */ s32 auxiliary_symbols_offset;
|
||||||
|
/* 0x38 */ s32 local_strings_size_bytes;
|
||||||
|
/* 0x3c */ s32 local_strings_offset;
|
||||||
|
/* 0x40 */ s32 external_strings_size_bytes;
|
||||||
|
/* 0x44 */ s32 external_strings_offset;
|
||||||
|
/* 0x48 */ s32 file_descriptor_count;
|
||||||
|
/* 0x4c */ s32 file_descriptors_offset;
|
||||||
|
/* 0x50 */ s32 relative_file_descriptor_count;
|
||||||
|
/* 0x54 */ s32 relative_file_descriptors_offset;
|
||||||
|
/* 0x58 */ s32 external_symbols_count;
|
||||||
|
/* 0x5c */ s32 external_symbols_offset;
|
||||||
|
)
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(FileDescriptor,
|
||||||
|
/* 0x00 */ u32 address;
|
||||||
|
/* 0x04 */ s32 file_path_string_offset;
|
||||||
|
/* 0x08 */ s32 strings_offset;
|
||||||
|
/* 0x0c */ s32 cb_ss;
|
||||||
|
/* 0x10 */ s32 isym_base;
|
||||||
|
/* 0x14 */ s32 symbol_count;
|
||||||
|
/* 0x18 */ s32 line_number_entry_index_base;
|
||||||
|
/* 0x1c */ s32 cline;
|
||||||
|
/* 0x20 */ s32 optimization_entry_index_base;
|
||||||
|
/* 0x24 */ s32 copt;
|
||||||
|
/* 0x28 */ u16 ipd_first;
|
||||||
|
/* 0x2a */ u16 procedure_descriptor_count;
|
||||||
|
/* 0x2c */ s32 iaux_base;
|
||||||
|
/* 0x30 */ s32 caux;
|
||||||
|
/* 0x34 */ s32 rfd_base;
|
||||||
|
/* 0x38 */ s32 crfd;
|
||||||
|
/* 0x3c */ u32 lang : 5;
|
||||||
|
/* 0x3c */ u32 f_merge : 1;
|
||||||
|
/* 0x3c */ u32 f_readin : 1;
|
||||||
|
/* 0x3c */ u32 f_big_endian : 1;
|
||||||
|
/* 0x3c */ u32 reserved_1 : 22;
|
||||||
|
/* 0x40 */ s32 line_number_offset;
|
||||||
|
/* 0x44 */ s32 cb_line;
|
||||||
|
)
|
||||||
|
static_assert(sizeof(FileDescriptor) == 0x48);
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(SymbolHeader,
|
||||||
|
/* 0x0 */ u32 iss;
|
||||||
|
/* 0x4 */ u32 value;
|
||||||
|
/* 0x8 */ u32 st : 6;
|
||||||
|
/* 0x8 */ u32 sc : 5;
|
||||||
|
/* 0x8 */ u32 reserved : 1;
|
||||||
|
/* 0x8 */ u32 index : 20;
|
||||||
|
)
|
||||||
|
static_assert(sizeof(SymbolHeader) == 0xc);
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(ExternalSymbolHeader,
|
||||||
|
/* 0x0 */ u16 flags;
|
||||||
|
/* 0x2 */ s16 ifd;
|
||||||
|
/* 0x4 */ SymbolHeader symbol;
|
||||||
|
)
|
||||||
|
static_assert(sizeof(ExternalSymbolHeader) == 0x10);
|
||||||
|
|
||||||
|
static void print_symbol(FILE* out, const Symbol& symbol);
|
||||||
|
static void print_procedure_descriptor(FILE* out, const ProcedureDescriptor& procedure_descriptor);
|
||||||
|
static Result<s32> get_corruption_fixing_fudge_offset(s32 section_offset, const SymbolicHeader& hdrr);
|
||||||
|
static Result<Symbol> get_symbol(const SymbolHeader& header, std::span<const u8> elf, s32 strings_offset);
|
||||||
|
|
||||||
|
Result<void> SymbolTableReader::init(std::span<const u8> elf, s32 section_offset)
|
||||||
|
{
|
||||||
|
m_elf = elf;
|
||||||
|
m_section_offset = section_offset;
|
||||||
|
|
||||||
|
m_hdrr = get_unaligned<SymbolicHeader>(m_elf, m_section_offset);
|
||||||
|
CCC_CHECK(m_hdrr != nullptr, "MIPS debug section header out of bounds.");
|
||||||
|
CCC_CHECK(m_hdrr->magic == 0x7009, "Invalid symbolic header.");
|
||||||
|
|
||||||
|
Result<s32> fudge_offset = get_corruption_fixing_fudge_offset(m_section_offset, *m_hdrr);
|
||||||
|
CCC_RETURN_IF_ERROR(fudge_offset);
|
||||||
|
m_fudge_offset = *fudge_offset;
|
||||||
|
|
||||||
|
m_ready = true;
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 SymbolTableReader::file_count() const
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_ready);
|
||||||
|
return m_hdrr->file_descriptor_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<File> SymbolTableReader::parse_file(s32 index) const
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_ready);
|
||||||
|
|
||||||
|
File file;
|
||||||
|
|
||||||
|
u64 fd_offset = m_hdrr->file_descriptors_offset + index * sizeof(FileDescriptor);
|
||||||
|
const FileDescriptor* fd_header = get_unaligned<FileDescriptor>(m_elf, fd_offset + m_fudge_offset);
|
||||||
|
CCC_CHECK(fd_header != nullptr, "MIPS debug file descriptor out of bounds.");
|
||||||
|
CCC_CHECK(fd_header->f_big_endian == 0, "Not little endian or bad file descriptor table.");
|
||||||
|
|
||||||
|
file.address = fd_header->address;
|
||||||
|
|
||||||
|
s32 rel_raw_path_offset = fd_header->strings_offset + fd_header->file_path_string_offset;
|
||||||
|
s32 raw_path_offset = m_hdrr->local_strings_offset + rel_raw_path_offset + m_fudge_offset;
|
||||||
|
std::optional<std::string_view> command_line_path = get_string(m_elf, raw_path_offset);
|
||||||
|
if(command_line_path.has_value()) {
|
||||||
|
file.command_line_path = *command_line_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse local symbols.
|
||||||
|
for(s64 j = 0; j < fd_header->symbol_count; j++) {
|
||||||
|
u64 rel_symbol_offset = (fd_header->isym_base + j) * sizeof(SymbolHeader);
|
||||||
|
u64 symbol_offset = m_hdrr->local_symbols_offset + rel_symbol_offset + m_fudge_offset;
|
||||||
|
const SymbolHeader* symbol_header = get_unaligned<SymbolHeader>(m_elf, symbol_offset);
|
||||||
|
CCC_CHECK(symbol_header != nullptr, "Symbol header out of bounds.");
|
||||||
|
|
||||||
|
s32 strings_offset = m_hdrr->local_strings_offset + fd_header->strings_offset + m_fudge_offset;
|
||||||
|
Result<Symbol> sym = get_symbol(*symbol_header, m_elf, strings_offset);
|
||||||
|
CCC_RETURN_IF_ERROR(sym);
|
||||||
|
|
||||||
|
bool string_offset_equal = (s32) symbol_header->iss == fd_header->file_path_string_offset;
|
||||||
|
if(file.working_dir.empty() && string_offset_equal && sym->is_stabs() && sym->code() == N_SO && file.symbols.size() > 2) {
|
||||||
|
const Symbol& working_dir = file.symbols.back();
|
||||||
|
if(working_dir.is_stabs() && working_dir.code() == N_SO) {
|
||||||
|
file.working_dir = working_dir.string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.symbols.emplace_back(std::move(*sym));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse procedure descriptors.
|
||||||
|
for(s64 i = 0; i < fd_header->procedure_descriptor_count; i++) {
|
||||||
|
u64 rel_procedure_offset = (fd_header->ipd_first + i) * sizeof(ProcedureDescriptor);
|
||||||
|
u64 procedure_offset = m_hdrr->procedure_descriptors_offset + rel_procedure_offset + m_fudge_offset;
|
||||||
|
const ProcedureDescriptor* procedure_descriptor = get_unaligned<ProcedureDescriptor>(m_elf, procedure_offset);
|
||||||
|
CCC_CHECK(procedure_descriptor != nullptr, "Procedure descriptor out of bounds.");
|
||||||
|
|
||||||
|
CCC_CHECK(procedure_descriptor->symbol_index < file.symbols.size(), "Symbol index out of bounds.");
|
||||||
|
file.symbols[procedure_descriptor->symbol_index].procedure_descriptor = procedure_descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
file.full_path = merge_paths(file.working_dir, file.command_line_path);
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::vector<Symbol>> SymbolTableReader::parse_external_symbols() const
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_ready);
|
||||||
|
|
||||||
|
std::vector<Symbol> external_symbols;
|
||||||
|
for(s64 i = 0; i < m_hdrr->external_symbols_count; i++) {
|
||||||
|
u64 sym_offset = m_hdrr->external_symbols_offset + i * sizeof(ExternalSymbolHeader);
|
||||||
|
const ExternalSymbolHeader* external_header = get_unaligned<ExternalSymbolHeader>(m_elf, sym_offset + m_fudge_offset);
|
||||||
|
CCC_CHECK(external_header != nullptr, "External header out of bounds.");
|
||||||
|
|
||||||
|
Result<Symbol> sym = get_symbol(external_header->symbol, m_elf, m_hdrr->external_strings_offset + m_fudge_offset);
|
||||||
|
CCC_RETURN_IF_ERROR(sym);
|
||||||
|
external_symbols.emplace_back(std::move(*sym));
|
||||||
|
}
|
||||||
|
|
||||||
|
return external_symbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SymbolTableReader::print_header(FILE* dest) const
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_ready);
|
||||||
|
|
||||||
|
fprintf(dest, "Symbolic Header, magic = %hx, vstamp = %hx:\n",
|
||||||
|
(u16) m_hdrr->magic,
|
||||||
|
(u16) m_hdrr->version_stamp);
|
||||||
|
fprintf(dest, "\n");
|
||||||
|
fprintf(dest, " Offset Size (Bytes) Count\n");
|
||||||
|
fprintf(dest, " ------ ------------ -----\n");
|
||||||
|
fprintf(dest, " Line Numbers 0x%-8x " "0x%-8x " "%-8d\n",
|
||||||
|
(u32) m_hdrr->line_numbers_offset,
|
||||||
|
(u32) m_hdrr->line_numbers_size_bytes,
|
||||||
|
m_hdrr->line_number_count);
|
||||||
|
fprintf(dest, " Dense Numbers 0x%-8x " "0x%-8x " "%-8d\n",
|
||||||
|
(u32) m_hdrr->dense_numbers_offset,
|
||||||
|
(u32) m_hdrr->dense_numbers_count * 8,
|
||||||
|
m_hdrr->dense_numbers_count);
|
||||||
|
fprintf(dest, " Procedure Descriptors 0x%-8x " "0x%-8x " "%-8d\n",
|
||||||
|
(u32) m_hdrr->procedure_descriptors_offset,
|
||||||
|
(u32) m_hdrr->procedure_descriptor_count * (u32) sizeof(ProcedureDescriptor),
|
||||||
|
m_hdrr->procedure_descriptor_count);
|
||||||
|
fprintf(dest, " Local Symbols 0x%-8x " "0x%-8x " "%-8d\n",
|
||||||
|
(u32) m_hdrr->local_symbols_offset,
|
||||||
|
(u32) m_hdrr->local_symbol_count * (u32) sizeof(SymbolHeader),
|
||||||
|
m_hdrr->local_symbol_count);
|
||||||
|
fprintf(dest, " Optimization Symbols 0x%-8x " "- " "%-8d\n",
|
||||||
|
(u32) m_hdrr->optimization_symbols_offset,
|
||||||
|
m_hdrr->optimization_symbols_count);
|
||||||
|
fprintf(dest, " Auxiliary Symbols 0x%-8x " "0x%-8x " "%-8d\n",
|
||||||
|
(u32) m_hdrr->auxiliary_symbols_offset,
|
||||||
|
(u32) m_hdrr->auxiliary_symbol_count * 4,
|
||||||
|
m_hdrr->auxiliary_symbol_count);
|
||||||
|
fprintf(dest, " Local Strings 0x%-8x " "0x%-8x " "-\n",
|
||||||
|
(u32) m_hdrr->local_strings_offset,
|
||||||
|
(u32) m_hdrr->local_strings_size_bytes);
|
||||||
|
fprintf(dest, " External Strings 0x%-8x " "0x%-8x " "-\n",
|
||||||
|
(u32) m_hdrr->external_strings_offset,
|
||||||
|
(u32) m_hdrr->external_strings_size_bytes);
|
||||||
|
fprintf(dest, " File Descriptors 0x%-8x " "0x%-8x " "%-8d\n",
|
||||||
|
(u32) m_hdrr->file_descriptors_offset,
|
||||||
|
(u32) m_hdrr->file_descriptor_count * (u32) sizeof(FileDescriptor),
|
||||||
|
m_hdrr->file_descriptor_count);
|
||||||
|
fprintf(dest, " Relative File Descriptors 0x%-8x " "0x%-8x " "%-8d\n",
|
||||||
|
(u32) m_hdrr->relative_file_descriptors_offset,
|
||||||
|
(u32) m_hdrr->relative_file_descriptor_count * 4,
|
||||||
|
m_hdrr->relative_file_descriptor_count);
|
||||||
|
fprintf(dest, " External Symbols 0x%-8x " "0x%-8x " "%-8d\n",
|
||||||
|
(u32) m_hdrr->external_symbols_offset,
|
||||||
|
(u32) m_hdrr->external_symbols_count * 16,
|
||||||
|
m_hdrr->external_symbols_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> SymbolTableReader::print_symbols(FILE* out, bool print_locals, bool print_procedure_descriptors, bool print_externals) const
|
||||||
|
{
|
||||||
|
if(print_locals || print_procedure_descriptors) {
|
||||||
|
s32 count = file_count();
|
||||||
|
for(s32 i = 0; i < count; i++) {
|
||||||
|
Result<File> file = parse_file(i);
|
||||||
|
CCC_RETURN_IF_ERROR(file);
|
||||||
|
|
||||||
|
fprintf(out, "FILE %s:\n", file->command_line_path.c_str());
|
||||||
|
for(const Symbol& symbol : file->symbols) {
|
||||||
|
if(print_locals || symbol.procedure_descriptor) {
|
||||||
|
print_symbol(out, symbol);
|
||||||
|
}
|
||||||
|
if(print_procedure_descriptors && symbol.procedure_descriptor) {
|
||||||
|
print_procedure_descriptor(out, *symbol.procedure_descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(print_externals) {
|
||||||
|
fprintf(out, "EXTERNAL SYMBOLS:\n");
|
||||||
|
Result<std::vector<Symbol>> external_symbols = parse_external_symbols();
|
||||||
|
CCC_RETURN_IF_ERROR(external_symbols);
|
||||||
|
for(const Symbol& symbol : *external_symbols) {
|
||||||
|
print_symbol(out, symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_symbol(FILE* out, const Symbol& symbol)
|
||||||
|
{
|
||||||
|
fprintf(out, " %8x ", symbol.value);
|
||||||
|
|
||||||
|
const char* symbol_type_str = symbol_type(symbol.symbol_type);
|
||||||
|
if(symbol_type_str) {
|
||||||
|
fprintf(out, "%-11s ", symbol_type_str);
|
||||||
|
} else {
|
||||||
|
fprintf(out, "ST(%7u) ", (u32) symbol.symbol_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* symbol_class_str = symbol_class(symbol.symbol_class);
|
||||||
|
if(symbol_class_str) {
|
||||||
|
fprintf(out, "%-4s ", symbol_class_str);
|
||||||
|
} else if ((u32) symbol.symbol_class == 0) {
|
||||||
|
fprintf(out, " ");
|
||||||
|
} else {
|
||||||
|
fprintf(out, "SC(%4u) ", (u32) symbol.symbol_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(symbol.is_stabs()) {
|
||||||
|
fprintf(out, "%-8s ", stabs_code_to_string(symbol.code()));
|
||||||
|
} else {
|
||||||
|
fprintf(out, "SI(%4u) ", symbol.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(out, "%s\n", symbol.string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_procedure_descriptor(FILE* out, const ProcedureDescriptor& procedure_descriptor)
|
||||||
|
{
|
||||||
|
fprintf(out, " Address 0x%08x\n", procedure_descriptor.address);
|
||||||
|
fprintf(out, " Symbol Index %d\n", procedure_descriptor.symbol_index);
|
||||||
|
fprintf(out, " Line Number Entry Index %d\n", procedure_descriptor.line_number_entry_index);
|
||||||
|
fprintf(out, " Saved Register Mask 0x%08x\n", procedure_descriptor.saved_register_mask);
|
||||||
|
fprintf(out, " Saved Register Offset %d\n", procedure_descriptor.saved_register_offset);
|
||||||
|
fprintf(out, " Optimization Entry Index %d\n", procedure_descriptor.optimization_entry_index);
|
||||||
|
fprintf(out, " Saved Float Register Mask 0x%08x\n", procedure_descriptor.saved_float_register_mask);
|
||||||
|
fprintf(out, " Saved Float Register Offset %d\n", procedure_descriptor.saved_float_register_offset);
|
||||||
|
fprintf(out, " Frame Size %d\n", procedure_descriptor.frame_size);
|
||||||
|
fprintf(out, " Frame Pointer Register %hd\n", procedure_descriptor.frame_pointer_register);
|
||||||
|
fprintf(out, " Return PC Register %hd\n", procedure_descriptor.return_pc_register);
|
||||||
|
fprintf(out, " Line Number Low %d\n", procedure_descriptor.line_number_low);
|
||||||
|
fprintf(out, " Line Number High %d\n", procedure_descriptor.line_number_high);
|
||||||
|
fprintf(out, " Line Number Offset %d\n", procedure_descriptor.line_number_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<s32> get_corruption_fixing_fudge_offset(s32 section_offset, const SymbolicHeader& hdrr)
|
||||||
|
{
|
||||||
|
// GCC will always put the first part of the symbol table right after the
|
||||||
|
// header, so if the header says it's somewhere else we know the section has
|
||||||
|
// probably been moved without updating its contents.
|
||||||
|
s32 right_after_header = INT32_MAX;
|
||||||
|
if(hdrr.line_numbers_offset > 0) right_after_header = std::min(hdrr.line_numbers_offset, right_after_header);
|
||||||
|
if(hdrr.dense_numbers_offset > 0) right_after_header = std::min(hdrr.dense_numbers_offset, right_after_header);
|
||||||
|
if(hdrr.procedure_descriptors_offset > 0) right_after_header = std::min(hdrr.procedure_descriptors_offset, right_after_header);
|
||||||
|
if(hdrr.local_symbols_offset > 0) right_after_header = std::min(hdrr.local_symbols_offset, right_after_header);
|
||||||
|
if(hdrr.optimization_symbols_offset > 0) right_after_header = std::min(hdrr.optimization_symbols_offset, right_after_header);
|
||||||
|
if(hdrr.auxiliary_symbols_offset > 0) right_after_header = std::min(hdrr.auxiliary_symbols_offset, right_after_header);
|
||||||
|
if(hdrr.local_strings_offset > 0) right_after_header = std::min(hdrr.local_strings_offset, right_after_header);
|
||||||
|
if(hdrr.external_strings_offset > 0) right_after_header = std::min(hdrr.external_strings_offset, right_after_header);
|
||||||
|
if(hdrr.file_descriptors_offset > 0) right_after_header = std::min(hdrr.file_descriptors_offset, right_after_header);
|
||||||
|
if(hdrr.relative_file_descriptors_offset > 0) right_after_header = std::min(hdrr.relative_file_descriptors_offset, right_after_header);
|
||||||
|
if(hdrr.external_symbols_offset > 0) right_after_header = std::min(hdrr.external_symbols_offset, right_after_header);
|
||||||
|
|
||||||
|
CCC_CHECK(right_after_header >= 0 && right_after_header < INT32_MAX, "Invalid symbolic header.");
|
||||||
|
|
||||||
|
// Figure out how much we need to adjust all the file offsets by.
|
||||||
|
s32 fudge_offset = section_offset - (right_after_header - sizeof(SymbolicHeader));
|
||||||
|
if(fudge_offset != 0) {
|
||||||
|
CCC_WARN("The .mdebug section was moved without updating its contents. Adjusting file offsets by %d bytes.", fudge_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fudge_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<Symbol> get_symbol(const SymbolHeader& header, std::span<const u8> elf, s32 strings_offset)
|
||||||
|
{
|
||||||
|
Symbol symbol;
|
||||||
|
|
||||||
|
std::optional<std::string_view> string = get_string(elf, strings_offset + header.iss);
|
||||||
|
CCC_CHECK(string.has_value(), "Symbol has invalid string.");
|
||||||
|
symbol.string = string->data();
|
||||||
|
|
||||||
|
symbol.value = header.value;
|
||||||
|
symbol.symbol_type = (SymbolType) header.st;
|
||||||
|
symbol.symbol_class = (SymbolClass) header.sc;
|
||||||
|
symbol.index = header.index;
|
||||||
|
|
||||||
|
if(symbol.is_stabs()) {
|
||||||
|
CCC_CHECK(stabs_code_to_string(symbol.code()) != nullptr, "Bad stabs symbol code '%x'.", symbol.code());
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* symbol_type(SymbolType type)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case SymbolType::NIL: return "NIL";
|
||||||
|
case SymbolType::GLOBAL: return "GLOBAL";
|
||||||
|
case SymbolType::STATIC: return "STATIC";
|
||||||
|
case SymbolType::PARAM: return "PARAM";
|
||||||
|
case SymbolType::LOCAL: return "LOCAL";
|
||||||
|
case SymbolType::LABEL: return "LABEL";
|
||||||
|
case SymbolType::PROC: return "PROC";
|
||||||
|
case SymbolType::BLOCK: return "BLOCK";
|
||||||
|
case SymbolType::END: return "END";
|
||||||
|
case SymbolType::MEMBER: return "MEMBER";
|
||||||
|
case SymbolType::TYPEDEF: return "TYPEDEF";
|
||||||
|
case SymbolType::FILE_SYMBOL: return "FILE";
|
||||||
|
case SymbolType::STATICPROC: return "STATICPROC";
|
||||||
|
case SymbolType::CONSTANT: return "CONSTANT";
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* symbol_class(SymbolClass symbol_class)
|
||||||
|
{
|
||||||
|
switch(symbol_class) {
|
||||||
|
case SymbolClass::NIL: return "NIL";
|
||||||
|
case SymbolClass::TEXT: return "TEXT";
|
||||||
|
case SymbolClass::DATA: return "DATA";
|
||||||
|
case SymbolClass::BSS: return "BSS";
|
||||||
|
case SymbolClass::REGISTER: return "REGISTER";
|
||||||
|
case SymbolClass::ABS: return "ABS";
|
||||||
|
case SymbolClass::UNDEFINED: return "UNDEFINED";
|
||||||
|
case SymbolClass::LOCAL: return "LOCAL";
|
||||||
|
case SymbolClass::BITS: return "BITS";
|
||||||
|
case SymbolClass::DBX: return "DBX";
|
||||||
|
case SymbolClass::REG_IMAGE: return "REG_IMAGE";
|
||||||
|
case SymbolClass::INFO: return "INFO";
|
||||||
|
case SymbolClass::USER_STRUCT: return "USER_STRUCT";
|
||||||
|
case SymbolClass::SDATA: return "SDATA";
|
||||||
|
case SymbolClass::SBSS: return "SBSS";
|
||||||
|
case SymbolClass::RDATA: return "RDATA";
|
||||||
|
case SymbolClass::VAR: return "VAR";
|
||||||
|
case SymbolClass::COMMON: return "COMMON";
|
||||||
|
case SymbolClass::SCOMMON: return "SCOMMON";
|
||||||
|
case SymbolClass::VAR_REGISTER: return "VAR_REGISTER";
|
||||||
|
case SymbolClass::VARIANT: return "VARIANT";
|
||||||
|
case SymbolClass::SUNDEFINED: return "SUNDEFINED";
|
||||||
|
case SymbolClass::INIT: return "INIT";
|
||||||
|
case SymbolClass::BASED_VAR: return "BASED_VAR";
|
||||||
|
case SymbolClass::XDATA: return "XDATA";
|
||||||
|
case SymbolClass::PDATA: return "PDATA";
|
||||||
|
case SymbolClass::FINI: return "FINI";
|
||||||
|
case SymbolClass::NONGP: return "NONGP";
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* stabs_code_to_string(StabsCode code)
|
||||||
|
{
|
||||||
|
switch(code) {
|
||||||
|
case STAB: return "STAB";
|
||||||
|
case N_GSYM: return "GSYM";
|
||||||
|
case N_FNAME: return "FNAME";
|
||||||
|
case N_FUN: return "FUN";
|
||||||
|
case N_STSYM: return "STSYM";
|
||||||
|
case N_LCSYM: return "LCSYM";
|
||||||
|
case N_MAIN: return "MAIN";
|
||||||
|
case N_PC: return "PC";
|
||||||
|
case N_NSYMS: return "NSYMS";
|
||||||
|
case N_NOMAP: return "NOMAP";
|
||||||
|
case N_OBJ: return "OBJ";
|
||||||
|
case N_OPT: return "OPT";
|
||||||
|
case N_RSYM: return "RSYM";
|
||||||
|
case N_M2C: return "M2C";
|
||||||
|
case N_SLINE: return "SLINE";
|
||||||
|
case N_DSLINE: return "DSLINE";
|
||||||
|
case N_BSLINE: return "BSLINE";
|
||||||
|
case N_EFD: return "EFD";
|
||||||
|
case N_EHDECL: return "EHDECL";
|
||||||
|
case N_CATCH: return "CATCH";
|
||||||
|
case N_SSYM: return "SSYM";
|
||||||
|
case N_SO: return "SO";
|
||||||
|
case N_LSYM: return "LSYM";
|
||||||
|
case N_BINCL: return "BINCL";
|
||||||
|
case N_SOL: return "SOL";
|
||||||
|
case N_PSYM: return "PSYM";
|
||||||
|
case N_EINCL: return "EINCL";
|
||||||
|
case N_ENTRY: return "ENTRY";
|
||||||
|
case N_LBRAC: return "LBRAC";
|
||||||
|
case N_EXCL: return "EXCL";
|
||||||
|
case N_SCOPE: return "SCOPE";
|
||||||
|
case N_RBRAC: return "RBRAC";
|
||||||
|
case N_BCOMM: return "BCOMM";
|
||||||
|
case N_ECOMM: return "ECOMM";
|
||||||
|
case N_ECOML: return "ECOML";
|
||||||
|
case N_NBTEXT: return "NBTEXT";
|
||||||
|
case N_NBDATA: return "NBDATA";
|
||||||
|
case N_NBBSS: return "NBBSS";
|
||||||
|
case N_NBSTS: return "NBSTS";
|
||||||
|
case N_NBLCS: return "NBLCS";
|
||||||
|
case N_LENG: return "LENG";
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace ccc::mdebug {
|
||||||
|
|
||||||
|
struct SymbolicHeader;
|
||||||
|
|
||||||
|
enum class SymbolType : u32 {
|
||||||
|
NIL = 0,
|
||||||
|
GLOBAL = 1,
|
||||||
|
STATIC = 2,
|
||||||
|
PARAM = 3,
|
||||||
|
LOCAL = 4,
|
||||||
|
LABEL = 5,
|
||||||
|
PROC = 6,
|
||||||
|
BLOCK = 7,
|
||||||
|
END = 8,
|
||||||
|
MEMBER = 9,
|
||||||
|
TYPEDEF = 10,
|
||||||
|
FILE_SYMBOL = 11,
|
||||||
|
STATICPROC = 14,
|
||||||
|
CONSTANT = 15
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SymbolClass : u32 {
|
||||||
|
NIL = 0,
|
||||||
|
TEXT = 1,
|
||||||
|
DATA = 2,
|
||||||
|
BSS = 3,
|
||||||
|
REGISTER = 4,
|
||||||
|
ABS = 5,
|
||||||
|
UNDEFINED = 6,
|
||||||
|
LOCAL = 7,
|
||||||
|
BITS = 8,
|
||||||
|
DBX = 9,
|
||||||
|
REG_IMAGE = 10,
|
||||||
|
INFO = 11,
|
||||||
|
USER_STRUCT = 12,
|
||||||
|
SDATA = 13,
|
||||||
|
SBSS = 14,
|
||||||
|
RDATA = 15,
|
||||||
|
VAR = 16,
|
||||||
|
COMMON = 17,
|
||||||
|
SCOMMON = 18,
|
||||||
|
VAR_REGISTER = 19,
|
||||||
|
VARIANT = 20,
|
||||||
|
SUNDEFINED = 21,
|
||||||
|
INIT = 22,
|
||||||
|
BASED_VAR = 23,
|
||||||
|
XDATA = 24,
|
||||||
|
PDATA = 25,
|
||||||
|
FINI = 26,
|
||||||
|
NONGP = 27
|
||||||
|
};
|
||||||
|
|
||||||
|
// See stab.def from gcc for documentation on what all these are.
|
||||||
|
enum StabsCode {
|
||||||
|
STAB = 0x00,
|
||||||
|
N_GSYM = 0x20,
|
||||||
|
N_FNAME = 0x22,
|
||||||
|
N_FUN = 0x24,
|
||||||
|
N_STSYM = 0x26,
|
||||||
|
N_LCSYM = 0x28,
|
||||||
|
N_MAIN = 0x2a,
|
||||||
|
N_PC = 0x30,
|
||||||
|
N_NSYMS = 0x32,
|
||||||
|
N_NOMAP = 0x34,
|
||||||
|
N_OBJ = 0x38,
|
||||||
|
N_OPT = 0x3c,
|
||||||
|
N_RSYM = 0x40,
|
||||||
|
N_M2C = 0x42,
|
||||||
|
N_SLINE = 0x44,
|
||||||
|
N_DSLINE = 0x46,
|
||||||
|
N_BSLINE = 0x48,
|
||||||
|
N_EFD = 0x4a,
|
||||||
|
N_EHDECL = 0x50,
|
||||||
|
N_CATCH = 0x54,
|
||||||
|
N_SSYM = 0x60,
|
||||||
|
N_SO = 0x64,
|
||||||
|
N_LSYM = 0x80,
|
||||||
|
N_BINCL = 0x82,
|
||||||
|
N_SOL = 0x84,
|
||||||
|
N_PSYM = 0xa0,
|
||||||
|
N_EINCL = 0xa2,
|
||||||
|
N_ENTRY = 0xa4,
|
||||||
|
N_LBRAC = 0xc0,
|
||||||
|
N_EXCL = 0xc2,
|
||||||
|
N_SCOPE = 0xc4,
|
||||||
|
N_RBRAC = 0xe0,
|
||||||
|
N_BCOMM = 0xe2,
|
||||||
|
N_ECOMM = 0xe4,
|
||||||
|
N_ECOML = 0xe8,
|
||||||
|
N_NBTEXT = 0xf0,
|
||||||
|
N_NBDATA = 0xf2,
|
||||||
|
N_NBBSS = 0xf4,
|
||||||
|
N_NBSTS = 0xf6,
|
||||||
|
N_NBLCS = 0xf8,
|
||||||
|
N_LENG = 0xfe
|
||||||
|
};
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(ProcedureDescriptor,
|
||||||
|
/* 0x00 */ u32 address;
|
||||||
|
/* 0x04 */ u32 symbol_index;
|
||||||
|
/* 0x08 */ s32 line_number_entry_index;
|
||||||
|
/* 0x0c */ s32 saved_register_mask;
|
||||||
|
/* 0x10 */ s32 saved_register_offset;
|
||||||
|
/* 0x14 */ s32 optimization_entry_index;
|
||||||
|
/* 0x18 */ s32 saved_float_register_mask;
|
||||||
|
/* 0x1c */ s32 saved_float_register_offset;
|
||||||
|
/* 0x20 */ s32 frame_size;
|
||||||
|
/* 0x24 */ s16 frame_pointer_register;
|
||||||
|
/* 0x26 */ s16 return_pc_register;
|
||||||
|
/* 0x28 */ s32 line_number_low;
|
||||||
|
/* 0x2c */ s32 line_number_high;
|
||||||
|
/* 0x30 */ u32 line_number_offset;
|
||||||
|
)
|
||||||
|
static_assert(sizeof(ProcedureDescriptor) == 0x34);
|
||||||
|
|
||||||
|
struct Symbol {
|
||||||
|
u32 value;
|
||||||
|
SymbolType symbol_type;
|
||||||
|
SymbolClass symbol_class;
|
||||||
|
u32 index;
|
||||||
|
const char* string;
|
||||||
|
const ProcedureDescriptor* procedure_descriptor = nullptr;
|
||||||
|
|
||||||
|
bool is_stabs() const {
|
||||||
|
return (index & 0xfff00) == 0x8f300;
|
||||||
|
}
|
||||||
|
|
||||||
|
StabsCode code() const {
|
||||||
|
return (StabsCode) (index - 0x8f300);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct File {
|
||||||
|
std::vector<Symbol> symbols;
|
||||||
|
u32 address = 0;
|
||||||
|
std::string working_dir; // The working directory of gcc.
|
||||||
|
std::string command_line_path; // The source file path passed on the command line to gcc.
|
||||||
|
std::string full_path; // The full combined path.
|
||||||
|
};
|
||||||
|
|
||||||
|
class SymbolTableReader {
|
||||||
|
public:
|
||||||
|
Result<void> init(std::span<const u8> elf, s32 section_offset);
|
||||||
|
|
||||||
|
s32 file_count() const;
|
||||||
|
Result<File> parse_file(s32 index) const;
|
||||||
|
Result<std::vector<Symbol>> parse_external_symbols() const;
|
||||||
|
|
||||||
|
void print_header(FILE* out) const;
|
||||||
|
Result<void> print_symbols(FILE* out, bool print_locals, bool print_procedure_descriptors, bool print_externals) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_ready = false;
|
||||||
|
|
||||||
|
std::span<const u8> m_elf;
|
||||||
|
s32 m_section_offset;
|
||||||
|
|
||||||
|
// If the .mdebug section was moved without updating its contents all the
|
||||||
|
// absolute file offsets stored within will be incorrect by a fixed amount.
|
||||||
|
s32 m_fudge_offset;
|
||||||
|
|
||||||
|
const SymbolicHeader* m_hdrr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* symbol_type(SymbolType type);
|
||||||
|
const char* symbol_class(SymbolClass symbol_class);
|
||||||
|
const char* stabs_code_to_string(StabsCode code);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,220 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "mdebug_symbols.h"
|
||||||
|
|
||||||
|
#include "importer_flags.h"
|
||||||
|
|
||||||
|
namespace ccc::mdebug {
|
||||||
|
|
||||||
|
static void mark_duplicate_symbols(std::vector<ParsedSymbol>& symbols);
|
||||||
|
|
||||||
|
Result<std::vector<ParsedSymbol>> parse_symbols(const std::vector<mdebug::Symbol>& input, u32& importer_flags)
|
||||||
|
{
|
||||||
|
std::vector<ParsedSymbol> output;
|
||||||
|
std::string prefix;
|
||||||
|
for(const mdebug::Symbol& symbol : input) {
|
||||||
|
if(symbol.is_stabs()) {
|
||||||
|
switch(symbol.code()) {
|
||||||
|
case mdebug::N_GSYM: // Global variable
|
||||||
|
case mdebug::N_FUN: // Function
|
||||||
|
case mdebug::N_STSYM: // Data section static global variable
|
||||||
|
case mdebug::N_LCSYM: // BSS section static global variable
|
||||||
|
case mdebug::N_RSYM: // Register variable
|
||||||
|
case mdebug::N_LSYM: // Automatic variable or type definition
|
||||||
|
case mdebug::N_PSYM: { // Parameter variable
|
||||||
|
// Some STABS symbols are split between multiple strings.
|
||||||
|
if(symbol.string[0] != '\0') {
|
||||||
|
if(symbol.string[strlen(symbol.string) - 1] == '\\') {
|
||||||
|
prefix += std::string(symbol.string, symbol.string + strlen(symbol.string) - 1);
|
||||||
|
} else {
|
||||||
|
std::string merged_string;
|
||||||
|
const char* string;
|
||||||
|
if(!prefix.empty()) {
|
||||||
|
merged_string = prefix + symbol.string;
|
||||||
|
string = merged_string.c_str();
|
||||||
|
prefix.clear();
|
||||||
|
} else {
|
||||||
|
string = symbol.string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* input = string;
|
||||||
|
Result<StabsSymbol> parse_result = parse_stabs_symbol(input);
|
||||||
|
if(parse_result.success()) {
|
||||||
|
if(*input != '\0') {
|
||||||
|
if(importer_flags & STRICT_PARSING) {
|
||||||
|
return CCC_FAILURE("Unknown data '%s' at the end of the '%s' stab.", input, parse_result->name.c_str());
|
||||||
|
} else {
|
||||||
|
CCC_WARN("Unknown data '%s' at the end of the '%s' stab.", input, parse_result->name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedSymbol& parsed = output.emplace_back();
|
||||||
|
parsed.type = ParsedSymbolType::NAME_COLON_TYPE;
|
||||||
|
parsed.raw = &symbol;
|
||||||
|
parsed.name_colon_type = std::move(*parse_result);
|
||||||
|
} else if(parse_result.error().message == STAB_TRUNCATED_ERROR_MESSAGE) {
|
||||||
|
// Symbol truncated due to a GCC bug. Report a
|
||||||
|
// warning and try to tolerate further faults
|
||||||
|
// caused as a result of this.
|
||||||
|
CCC_WARN("%s Symbol string: %s", STAB_TRUNCATED_ERROR_MESSAGE, string);
|
||||||
|
importer_flags &= ~STRICT_PARSING;
|
||||||
|
} else {
|
||||||
|
return CCC_FAILURE("%s Symbol string: %s",
|
||||||
|
parse_result.error().message.c_str(), string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CCC_CHECK(prefix.empty(), "Invalid STABS continuation.");
|
||||||
|
if(symbol.code() == mdebug::N_FUN) {
|
||||||
|
ParsedSymbol& func_end = output.emplace_back();
|
||||||
|
func_end.type = ParsedSymbolType::FUNCTION_END;
|
||||||
|
func_end.raw = &symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case mdebug::N_SOL: { // Sub-source file
|
||||||
|
ParsedSymbol& sub = output.emplace_back();
|
||||||
|
sub.type = ParsedSymbolType::SUB_SOURCE_FILE;
|
||||||
|
sub.raw = &symbol;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case mdebug::N_LBRAC: { // Begin block
|
||||||
|
ParsedSymbol& begin_block = output.emplace_back();
|
||||||
|
begin_block.type = ParsedSymbolType::LBRAC;
|
||||||
|
begin_block.raw = &symbol;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case mdebug::N_RBRAC: { // End block
|
||||||
|
ParsedSymbol& end_block = output.emplace_back();
|
||||||
|
end_block.type = ParsedSymbolType::RBRAC;
|
||||||
|
end_block.raw = &symbol;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case mdebug::N_SO: { // Source filename
|
||||||
|
ParsedSymbol& so_symbol = output.emplace_back();
|
||||||
|
so_symbol.type = ParsedSymbolType::SOURCE_FILE;
|
||||||
|
so_symbol.raw = &symbol;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case mdebug::STAB:
|
||||||
|
case mdebug::N_OPT:
|
||||||
|
case mdebug::N_BINCL:
|
||||||
|
case mdebug::N_EINCL: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case mdebug::N_FNAME:
|
||||||
|
case mdebug::N_MAIN:
|
||||||
|
case mdebug::N_PC:
|
||||||
|
case mdebug::N_NSYMS:
|
||||||
|
case mdebug::N_NOMAP:
|
||||||
|
case mdebug::N_OBJ:
|
||||||
|
case mdebug::N_M2C:
|
||||||
|
case mdebug::N_SLINE:
|
||||||
|
case mdebug::N_DSLINE:
|
||||||
|
case mdebug::N_BSLINE:
|
||||||
|
case mdebug::N_EFD:
|
||||||
|
case mdebug::N_EHDECL:
|
||||||
|
case mdebug::N_CATCH:
|
||||||
|
case mdebug::N_SSYM:
|
||||||
|
case mdebug::N_ENTRY:
|
||||||
|
case mdebug::N_EXCL:
|
||||||
|
case mdebug::N_SCOPE:
|
||||||
|
case mdebug::N_BCOMM:
|
||||||
|
case mdebug::N_ECOMM:
|
||||||
|
case mdebug::N_ECOML:
|
||||||
|
case mdebug::N_NBTEXT:
|
||||||
|
case mdebug::N_NBDATA:
|
||||||
|
case mdebug::N_NBBSS:
|
||||||
|
case mdebug::N_NBSTS:
|
||||||
|
case mdebug::N_NBLCS:
|
||||||
|
case mdebug::N_LENG: {
|
||||||
|
CCC_WARN("Unhandled N_%s symbol: %s", mdebug::stabs_code_to_string(symbol.code()), symbol.string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ParsedSymbol& non_stabs_symbol = output.emplace_back();
|
||||||
|
non_stabs_symbol.type = ParsedSymbolType::NON_STABS;
|
||||||
|
non_stabs_symbol.raw = &symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_duplicate_symbols(output);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mark_duplicate_symbols(std::vector<ParsedSymbol>& symbols)
|
||||||
|
{
|
||||||
|
std::map<StabsTypeNumber, size_t> stabs_type_number_to_symbol;
|
||||||
|
for(size_t i = 0; i < symbols.size(); i++) {
|
||||||
|
ParsedSymbol& symbol = symbols[i];
|
||||||
|
if(symbol.type == ParsedSymbolType::NAME_COLON_TYPE) {
|
||||||
|
StabsType& type = *symbol.name_colon_type.type;
|
||||||
|
if(type.type_number.valid() && type.descriptor.has_value()) {
|
||||||
|
stabs_type_number_to_symbol.emplace(type.type_number, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(ParsedSymbol& symbol : symbols) {
|
||||||
|
symbol.is_typedef =
|
||||||
|
symbol.type == ParsedSymbolType::NAME_COLON_TYPE &&
|
||||||
|
symbol.name_colon_type.descriptor == StabsSymbolDescriptor::TYPE_NAME &&
|
||||||
|
symbol.name_colon_type.type->descriptor != StabsTypeDescriptor::ENUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < symbols.size(); i++) {
|
||||||
|
ParsedSymbol& symbol = symbols[i];
|
||||||
|
if(symbol.type != ParsedSymbolType::NAME_COLON_TYPE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_type =
|
||||||
|
symbol.name_colon_type.descriptor == StabsSymbolDescriptor::TYPE_NAME ||
|
||||||
|
symbol.name_colon_type.descriptor == StabsSymbolDescriptor::ENUM_STRUCT_OR_TYPE_TAG;
|
||||||
|
if(!is_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
StabsType& type = *symbol.name_colon_type.type;
|
||||||
|
|
||||||
|
if(!type.descriptor.has_value()) {
|
||||||
|
auto referenced_index = stabs_type_number_to_symbol.find(type.type_number);
|
||||||
|
if(referenced_index != stabs_type_number_to_symbol.end()) {
|
||||||
|
ParsedSymbol& referenced = symbols[referenced_index->second];
|
||||||
|
if(referenced.name_colon_type.name == symbol.name_colon_type.name) {
|
||||||
|
// symbol: "Struct:T(1,1)=s1;"
|
||||||
|
// referenced: "Struct:t(1,1)"
|
||||||
|
symbol.duplicate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type.descriptor.has_value() && type.descriptor == StabsTypeDescriptor::TYPE_REFERENCE) {
|
||||||
|
auto referenced_index = stabs_type_number_to_symbol.find(type.as<StabsTypeReferenceType>().type->type_number);
|
||||||
|
if(referenced_index != stabs_type_number_to_symbol.end() && referenced_index->second != i) {
|
||||||
|
ParsedSymbol& referenced = symbols[referenced_index->second];
|
||||||
|
|
||||||
|
if(referenced.name_colon_type.name == " ") {
|
||||||
|
// referenced: " :T(1,1)=e;"
|
||||||
|
// symbol: "ErraticEnum:t(1,2)=(1,1)"
|
||||||
|
referenced.name_colon_type.name = symbol.name_colon_type.name;
|
||||||
|
referenced.is_typedef = true;
|
||||||
|
symbol.duplicate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(referenced.name_colon_type.name == symbol.name_colon_type.name) {
|
||||||
|
// referenced: "NamedTypedefedStruct:T(1,1)=s1;"
|
||||||
|
// symbol: "NamedTypedefedStruct:t(1,2)=(1,1)"
|
||||||
|
referenced.is_typedef = true;
|
||||||
|
symbol.duplicate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "stabs.h"
|
||||||
|
#include "mdebug_section.h"
|
||||||
|
|
||||||
|
namespace ccc::mdebug {
|
||||||
|
|
||||||
|
enum class ParsedSymbolType {
|
||||||
|
NAME_COLON_TYPE,
|
||||||
|
SOURCE_FILE,
|
||||||
|
SUB_SOURCE_FILE,
|
||||||
|
LBRAC,
|
||||||
|
RBRAC,
|
||||||
|
FUNCTION_END,
|
||||||
|
NON_STABS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParsedSymbol {
|
||||||
|
ParsedSymbolType type;
|
||||||
|
const mdebug::Symbol* raw;
|
||||||
|
StabsSymbol name_colon_type;
|
||||||
|
bool duplicate = false;
|
||||||
|
bool is_typedef = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<std::vector<ParsedSymbol>> parse_symbols(const std::vector<mdebug::Symbol>& input, u32& importer_flags);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "sndll.h"
|
||||||
|
|
||||||
|
#include "importer_flags.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(SNDLLHeaderCommon,
|
||||||
|
/* 0x00 */ u32 magic;
|
||||||
|
/* 0x04 */ u32 relocations;
|
||||||
|
/* 0x08 */ u32 relocation_count;
|
||||||
|
/* 0x0c */ u32 symbols;
|
||||||
|
/* 0x10 */ u32 symbol_count;
|
||||||
|
/* 0x14 */ u32 elf_path;
|
||||||
|
/* 0x18 */ u32 load_func;
|
||||||
|
/* 0x1c */ u32 unload_func;
|
||||||
|
/* 0x20 */ u32 unknown_20;
|
||||||
|
/* 0x24 */ u32 unknown_24;
|
||||||
|
/* 0x28 */ u32 unknown_28;
|
||||||
|
/* 0x2c */ u32 file_size;
|
||||||
|
/* 0x30 */ u32 unknown_30;
|
||||||
|
)
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(SNDLLHeaderV1,
|
||||||
|
/* 0x00 */ SNDLLHeaderCommon common;
|
||||||
|
)
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(SNDLLHeaderV2,
|
||||||
|
/* 0x00 */ SNDLLHeaderCommon common;
|
||||||
|
/* 0x34 */ u32 unknown_34;
|
||||||
|
/* 0x38 */ u32 unknown_38;
|
||||||
|
)
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(SNDLLRelocation,
|
||||||
|
/* 0x0 */ u32 unknown_0;
|
||||||
|
/* 0x4 */ u32 unknown_4;
|
||||||
|
/* 0x8 */ u32 unknown_8;
|
||||||
|
)
|
||||||
|
|
||||||
|
CCC_PACKED_STRUCT(SNDLLSymbolHeader,
|
||||||
|
/* 0x0 */ u32 string;
|
||||||
|
/* 0x4 */ u32 value;
|
||||||
|
/* 0x8 */ u8 unknown_8;
|
||||||
|
/* 0x9 */ u8 unknown_9;
|
||||||
|
/* 0xa */ SNDLLSymbolType type;
|
||||||
|
/* 0xb */ u8 processed;
|
||||||
|
)
|
||||||
|
|
||||||
|
static Result<SNDLLFile> parse_sndll_common(
|
||||||
|
std::span<const u8> image, Address address, SNDLLType type, const SNDLLHeaderCommon& common, SNDLLVersion version);
|
||||||
|
static const char* sndll_symbol_type_to_string(SNDLLSymbolType type);
|
||||||
|
|
||||||
|
Result<SNDLLFile> parse_sndll_file(std::span<const u8> image, Address address, SNDLLType type)
|
||||||
|
{
|
||||||
|
std::optional<u32> magic = copy_unaligned<u32>(image, 0);
|
||||||
|
CCC_CHECK(magic.has_value(), "Failed to read SNDLL header.");
|
||||||
|
CCC_CHECK((*magic & 0xffffff) == CCC_FOURCC("SNR\00"), "Not a SNDLL %s.", address.valid() ? "section" : "file");
|
||||||
|
|
||||||
|
char version = *magic >> 24;
|
||||||
|
switch(version) {
|
||||||
|
case '1': {
|
||||||
|
const SNDLLHeaderV1* header = get_unaligned<SNDLLHeaderV1>(image, 0);
|
||||||
|
CCC_CHECK(header, "File too small to contain SNDLL V1 header.");
|
||||||
|
return parse_sndll_common(image, address, type, header->common, SNDLL_V1);
|
||||||
|
}
|
||||||
|
case '2': {
|
||||||
|
const SNDLLHeaderV2* header = get_unaligned<SNDLLHeaderV2>(image, 0);
|
||||||
|
CCC_CHECK(header, "File too small to contain SNDLL V2 header.");
|
||||||
|
return parse_sndll_common(image, address, type, header->common, SNDLL_V2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CCC_FAILURE("Unknown SNDLL version '%c'.", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<SNDLLFile> parse_sndll_common(
|
||||||
|
std::span<const u8> image, Address address, SNDLLType type, const SNDLLHeaderCommon& common, SNDLLVersion version)
|
||||||
|
{
|
||||||
|
SNDLLFile sndll;
|
||||||
|
|
||||||
|
sndll.address = address;
|
||||||
|
sndll.type = type;
|
||||||
|
sndll.version = version;
|
||||||
|
|
||||||
|
if(common.elf_path) {
|
||||||
|
std::optional<std::string_view> elf_path = get_string(image, common.elf_path);
|
||||||
|
CCC_CHECK(elf_path.has_value(), "SNDLL header has invalid ELF path field.");
|
||||||
|
sndll.elf_path = *elf_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCC_CHECK(common.symbol_count < (32 * 1024 * 1024) / sizeof(SNDLLSymbol), "SNDLL symbol count is too high.");
|
||||||
|
sndll.symbols.reserve(common.symbol_count);
|
||||||
|
|
||||||
|
for(u32 i = 0; i < common.symbol_count; i++) {
|
||||||
|
u32 symbol_offset = common.symbols - address.get_or_zero() + i * sizeof(SNDLLSymbolHeader);
|
||||||
|
const SNDLLSymbolHeader* symbol_header = get_unaligned<SNDLLSymbolHeader>(image, symbol_offset);
|
||||||
|
CCC_CHECK(symbol_header, "SNDLL symbol out of range.");
|
||||||
|
|
||||||
|
std::optional<std::string_view> string;
|
||||||
|
if(symbol_header->string) {
|
||||||
|
string = get_string(image, symbol_header->string - address.get_or_zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
SNDLLSymbol& symbol = sndll.symbols.emplace_back();
|
||||||
|
symbol.type = symbol_header->type;
|
||||||
|
symbol.value = symbol_header->value;
|
||||||
|
if(string.has_value()) {
|
||||||
|
symbol.string = *string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sndll;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> import_sndll_symbols(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SNDLLFile& sndll,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler)
|
||||||
|
{
|
||||||
|
for(const SNDLLSymbol& symbol : sndll.symbols) {
|
||||||
|
if(symbol.value == 0 || symbol.string.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 address = symbol.value;
|
||||||
|
if(symbol.type != SNDLL_ABSOLUTE && sndll.type == SNDLLType::DYNAMIC_LIBRARY) {
|
||||||
|
address += sndll.address.get_or_zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(importer_flags & DONT_DEDUPLICATE_SYMBOLS)) {
|
||||||
|
if(database.functions.first_handle_from_starting_address(address).valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(database.global_variables.first_handle_from_starting_address(address).valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(database.local_variables.first_handle_from_starting_address(address).valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Section* section = database.sections.symbol_overlapping_address(address);
|
||||||
|
if(section) {
|
||||||
|
if(section->contains_code()) {
|
||||||
|
Result<Function*> function = database.functions.create_symbol(
|
||||||
|
symbol.string, group.source, group.module_symbol, address, importer_flags, demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(function);
|
||||||
|
continue;
|
||||||
|
} else if(section->contains_data()) {
|
||||||
|
Result<GlobalVariable*> global_variable = database.global_variables.create_symbol(
|
||||||
|
symbol.string, group.source, group.module_symbol, address, importer_flags, demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(global_variable);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Label*> label = database.labels.create_symbol(
|
||||||
|
symbol.string, group.source, group.module_symbol, address, importer_flags, demangler);
|
||||||
|
CCC_RETURN_IF_ERROR(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_sndll_symbols(FILE* out, const SNDLLFile& sndll)
|
||||||
|
{
|
||||||
|
fprintf(out, "SNDLL SYMBOLS:\n");
|
||||||
|
for(const SNDLLSymbol& symbol : sndll.symbols) {
|
||||||
|
const char* type = sndll_symbol_type_to_string(symbol.type);
|
||||||
|
const char* string = !symbol.string.empty() ? symbol.string.c_str() : "(no string)";
|
||||||
|
fprintf(out, "%8s %08x %s\n", type, symbol.value, string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* sndll_symbol_type_to_string(SNDLLSymbolType type)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case SNDLL_NIL: return "NIL";
|
||||||
|
case SNDLL_EXTERNAL: return "EXTERNAL";
|
||||||
|
case SNDLL_RELATIVE: return "RELATIVE";
|
||||||
|
case SNDLL_WEAK: return "WEAK";
|
||||||
|
case SNDLL_ABSOLUTE: return "ABSOLUTE";
|
||||||
|
}
|
||||||
|
return "invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "symbol_database.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
enum class SNDLLType {
|
||||||
|
SNDATA_SECTION,
|
||||||
|
DYNAMIC_LIBRARY
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SNDLLVersion {
|
||||||
|
SNDLL_V1,
|
||||||
|
SNDLL_V2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SNDLLSymbolType : u8 {
|
||||||
|
SNDLL_NIL = 0, // I think this is just so that the first real symbol has an index of 1.
|
||||||
|
SNDLL_EXTERNAL = 1, // Symbol with an empty value, to be filled in from another module.
|
||||||
|
SNDLL_RELATIVE = 2, // Global symbol, value is relative to the start of the SNDLL file.
|
||||||
|
SNDLL_WEAK = 3, // Weak symbol, value is relative to the start of the SNDLL file.
|
||||||
|
SNDLL_ABSOLUTE = 4 // Global symbol, value is an absolute address.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SNDLLSymbol {
|
||||||
|
SNDLLSymbolType type = SNDLL_NIL;
|
||||||
|
u32 value = 0;
|
||||||
|
std::string string;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SNDLLFile {
|
||||||
|
Address address;
|
||||||
|
SNDLLType type;
|
||||||
|
SNDLLVersion version;
|
||||||
|
std::string elf_path;
|
||||||
|
std::vector<SNDLLSymbol> symbols;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If a valid address is passed, the pointers in the header will be treated as
|
||||||
|
// addresses, otherwise they will be treated as file offsets.
|
||||||
|
Result<SNDLLFile> parse_sndll_file(std::span<const u8> image, Address address, SNDLLType type);
|
||||||
|
|
||||||
|
Result<void> import_sndll_symbols(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SNDLLFile& sndll,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler);
|
||||||
|
|
||||||
|
void print_sndll_symbols(FILE* out, const SNDLLFile& sndll);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,835 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "stabs.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
#define STABS_DEBUG(...) //__VA_ARGS__
|
||||||
|
#define STABS_DEBUG_PRINTF(...) STABS_DEBUG(printf(__VA_ARGS__);)
|
||||||
|
|
||||||
|
static bool validate_symbol_descriptor(StabsSymbolDescriptor descriptor);
|
||||||
|
static Result<std::unique_ptr<StabsType>> parse_stabs_type(const char*& input);
|
||||||
|
static Result<std::vector<StabsStructOrUnionType::Field>> parse_field_list(const char*& input);
|
||||||
|
static Result<std::vector<StabsStructOrUnionType::MemberFunctionSet>> parse_member_functions(const char*& input);
|
||||||
|
static Result<StabsStructOrUnionType::Visibility> parse_visibility_character(const char*& input);
|
||||||
|
STABS_DEBUG(static void print_field(const StabsStructOrUnionType::Field& field);)
|
||||||
|
|
||||||
|
const char* STAB_TRUNCATED_ERROR_MESSAGE =
|
||||||
|
"STABS symbol truncated. This was probably caused by a GCC bug. "
|
||||||
|
"Other symbols from the same translation unit may also be invalid.";
|
||||||
|
|
||||||
|
Result<StabsSymbol> parse_stabs_symbol(const char*& input)
|
||||||
|
{
|
||||||
|
STABS_DEBUG_PRINTF("PARSING %s\n", input);
|
||||||
|
|
||||||
|
StabsSymbol symbol;
|
||||||
|
|
||||||
|
Result<std::string> name = parse_dodgy_stabs_identifier(input, ':');
|
||||||
|
CCC_RETURN_IF_ERROR(name);
|
||||||
|
|
||||||
|
symbol.name = *name;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ':', "identifier");
|
||||||
|
CCC_CHECK(*input != '\0', "Unexpected end of input.");
|
||||||
|
if((*input >= '0' && *input <= '9') || *input == '(') {
|
||||||
|
symbol.descriptor = StabsSymbolDescriptor::LOCAL_VARIABLE;
|
||||||
|
} else {
|
||||||
|
char symbol_descriptor = *(input++);
|
||||||
|
CCC_CHECK(symbol_descriptor != '\0', "Failed to parse symbol descriptor.");
|
||||||
|
symbol.descriptor = (StabsSymbolDescriptor) symbol_descriptor;
|
||||||
|
}
|
||||||
|
CCC_CHECK(validate_symbol_descriptor(symbol.descriptor),
|
||||||
|
"Invalid symbol descriptor '%c'.",
|
||||||
|
(char) symbol.descriptor);
|
||||||
|
CCC_CHECK(*input != '\0', "Unexpected end of input.");
|
||||||
|
if(*input == 't') {
|
||||||
|
input++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type = parse_top_level_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
|
||||||
|
// Handle nested functions.
|
||||||
|
bool is_function =
|
||||||
|
symbol.descriptor == StabsSymbolDescriptor::LOCAL_FUNCTION ||
|
||||||
|
symbol.descriptor == StabsSymbolDescriptor::GLOBAL_FUNCTION;
|
||||||
|
if(is_function && input[0] == ',') {
|
||||||
|
input++;
|
||||||
|
while(*input != ',' && *input != '\0') input++; // enclosing function
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "nested function suffix");
|
||||||
|
while(*input != ',' && *input != '\0') input++; // function
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol.type = std::move(*type);
|
||||||
|
|
||||||
|
// Make sure that variable names aren't used as type names e.g. the STABS
|
||||||
|
// symbol "somevar:P123=*456" may be referenced by the type number 123, but
|
||||||
|
// the type name is not "somevar".
|
||||||
|
bool is_type = symbol.descriptor == StabsSymbolDescriptor::TYPE_NAME
|
||||||
|
|| symbol.descriptor == StabsSymbolDescriptor::ENUM_STRUCT_OR_TYPE_TAG;
|
||||||
|
if(is_type) {
|
||||||
|
symbol.type->name = symbol.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol.type->is_typedef = symbol.descriptor == StabsSymbolDescriptor::TYPE_NAME;
|
||||||
|
symbol.type->is_root = true;
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool validate_symbol_descriptor(StabsSymbolDescriptor descriptor)
|
||||||
|
{
|
||||||
|
bool valid;
|
||||||
|
switch(descriptor) {
|
||||||
|
case StabsSymbolDescriptor::LOCAL_VARIABLE:
|
||||||
|
case StabsSymbolDescriptor::REFERENCE_PARAMETER_A:
|
||||||
|
case StabsSymbolDescriptor::LOCAL_FUNCTION:
|
||||||
|
case StabsSymbolDescriptor::GLOBAL_FUNCTION:
|
||||||
|
case StabsSymbolDescriptor::GLOBAL_VARIABLE:
|
||||||
|
case StabsSymbolDescriptor::REGISTER_PARAMETER:
|
||||||
|
case StabsSymbolDescriptor::VALUE_PARAMETER:
|
||||||
|
case StabsSymbolDescriptor::REGISTER_VARIABLE:
|
||||||
|
case StabsSymbolDescriptor::STATIC_GLOBAL_VARIABLE:
|
||||||
|
case StabsSymbolDescriptor::TYPE_NAME:
|
||||||
|
case StabsSymbolDescriptor::ENUM_STRUCT_OR_TYPE_TAG:
|
||||||
|
case StabsSymbolDescriptor::STATIC_LOCAL_VARIABLE:
|
||||||
|
case StabsSymbolDescriptor::REFERENCE_PARAMETER_V:
|
||||||
|
valid = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::unique_ptr<StabsType>> parse_top_level_stabs_type(const char*& input)
|
||||||
|
{
|
||||||
|
Result<std::unique_ptr<StabsType>> type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
|
||||||
|
// Handle first base class suffixes.
|
||||||
|
if((*type)->descriptor == StabsTypeDescriptor::STRUCT && input[0] == '~' && input[1] == '%') {
|
||||||
|
input += 2;
|
||||||
|
|
||||||
|
Result<std::unique_ptr<StabsType>> first_base_class = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(first_base_class);
|
||||||
|
(*type)->as<StabsStructType>().first_base_class = std::move(*first_base_class);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "first base class suffix");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle extra live range information.
|
||||||
|
if(input[0] == ';' && input[1] == 'l') {
|
||||||
|
input += 2;
|
||||||
|
CCC_EXPECT_CHAR(input, '(', "live range suffix");
|
||||||
|
CCC_EXPECT_CHAR(input, '#', "live range suffix");
|
||||||
|
std::optional<s32> start = parse_number_s32(input);
|
||||||
|
CCC_CHECK(start.has_value(), "Failed to parse live range suffix.");
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "live range suffix");
|
||||||
|
CCC_EXPECT_CHAR(input, '#', "live range suffix");
|
||||||
|
std::optional<s32> end = parse_number_s32(input);
|
||||||
|
CCC_CHECK(end.has_value(), "Failed to parse live range suffix.");
|
||||||
|
CCC_EXPECT_CHAR(input, ')', "live range suffix");
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<std::unique_ptr<StabsType>> parse_stabs_type(const char*& input)
|
||||||
|
{
|
||||||
|
StabsTypeNumber type_number;
|
||||||
|
|
||||||
|
CCC_CHECK(*input != '\0', "Unexpected end of input.");
|
||||||
|
|
||||||
|
if(*input == '(') {
|
||||||
|
// This file has type numbers made up of two pieces: an include file
|
||||||
|
// index and a type number.
|
||||||
|
|
||||||
|
input++;
|
||||||
|
|
||||||
|
std::optional<s32> file_index = parse_number_s32(input);
|
||||||
|
CCC_CHECK(file_index.has_value(), "Failed to parse type number (file index).");
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "type number");
|
||||||
|
|
||||||
|
std::optional<s32> type_index = parse_number_s32(input);
|
||||||
|
CCC_CHECK(type_index.has_value(), "Failed to parse type number (type index).");
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ')', "type number");
|
||||||
|
|
||||||
|
type_number.file = *file_index;
|
||||||
|
type_number.type = *type_index;
|
||||||
|
|
||||||
|
if(*input != '=') {
|
||||||
|
return std::make_unique<StabsType>(type_number);
|
||||||
|
}
|
||||||
|
input++;
|
||||||
|
} else if(*input >= '0' && *input <= '9') {
|
||||||
|
// This file has type numbers which are just a single number. This is
|
||||||
|
// the more common case for games.
|
||||||
|
|
||||||
|
std::optional<s32> type_index = parse_number_s32(input);
|
||||||
|
CCC_CHECK(type_index.has_value(), "Failed to parse type number.");
|
||||||
|
type_number.type = *type_index;
|
||||||
|
|
||||||
|
if(*input != '=') {
|
||||||
|
return std::make_unique<StabsType>(type_number);
|
||||||
|
}
|
||||||
|
input++;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCC_CHECK(*input != '\0', "Unexpected end of input.");
|
||||||
|
|
||||||
|
StabsTypeDescriptor descriptor;
|
||||||
|
if((*input >= '0' && *input <= '9') || *input == '(') {
|
||||||
|
descriptor = StabsTypeDescriptor::TYPE_REFERENCE;
|
||||||
|
} else {
|
||||||
|
char descriptor_char = *(input++);
|
||||||
|
CCC_CHECK(descriptor_char != '\0', "Failed to parse type descriptor.");
|
||||||
|
descriptor = (StabsTypeDescriptor) descriptor_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<StabsType> out_type;
|
||||||
|
|
||||||
|
switch(descriptor) {
|
||||||
|
case StabsTypeDescriptor::TYPE_REFERENCE: { // 0..9
|
||||||
|
auto type_reference = std::make_unique<StabsTypeReferenceType>(type_number);
|
||||||
|
|
||||||
|
auto type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
type_reference->type = std::move(*type);
|
||||||
|
|
||||||
|
out_type = std::move(type_reference);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::ARRAY: { // a
|
||||||
|
auto array = std::make_unique<StabsArrayType>(type_number);
|
||||||
|
|
||||||
|
auto index_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(index_type);
|
||||||
|
array->index_type = std::move(*index_type);
|
||||||
|
|
||||||
|
auto element_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(element_type);
|
||||||
|
array->element_type = std::move(*element_type);
|
||||||
|
|
||||||
|
out_type = std::move(array);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::ENUM: { // e
|
||||||
|
auto enum_type = std::make_unique<StabsEnumType>(type_number);
|
||||||
|
STABS_DEBUG_PRINTF("enum {\n");
|
||||||
|
while(*input != ';') {
|
||||||
|
std::optional<std::string> name = parse_stabs_identifier(input, ':');
|
||||||
|
CCC_CHECK(name.has_value(), "Failed to parse enum field name.");
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ':', "enum");
|
||||||
|
|
||||||
|
std::optional<s32> value = parse_number_s32(input);
|
||||||
|
CCC_CHECK(value.has_value(), "Failed to parse enum value.");
|
||||||
|
|
||||||
|
enum_type->fields.emplace_back(*value, std::move(*name));
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "enum");
|
||||||
|
}
|
||||||
|
input++;
|
||||||
|
STABS_DEBUG_PRINTF("}\n");
|
||||||
|
|
||||||
|
out_type = std::move(enum_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::FUNCTION: { // f
|
||||||
|
auto function = std::make_unique<StabsFunctionType>(type_number);
|
||||||
|
|
||||||
|
auto return_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(return_type);
|
||||||
|
function->return_type = std::move(*return_type);
|
||||||
|
|
||||||
|
out_type = std::move(function);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::VOLATILE_QUALIFIER: { // B
|
||||||
|
auto volatile_qualifier = std::make_unique<StabsVolatileQualifierType>(type_number);
|
||||||
|
|
||||||
|
auto type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
volatile_qualifier->type = std::move(*type);
|
||||||
|
|
||||||
|
out_type = std::move(volatile_qualifier);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::CONST_QUALIFIER: { // k
|
||||||
|
auto const_qualifier = std::make_unique<StabsConstQualifierType>(type_number);
|
||||||
|
|
||||||
|
auto type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
const_qualifier->type = std::move(*type);
|
||||||
|
|
||||||
|
out_type = std::move(const_qualifier);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::RANGE: { // r
|
||||||
|
auto range = std::make_unique<StabsRangeType>(type_number);
|
||||||
|
|
||||||
|
auto type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
range->type = std::move(*type);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "range type descriptor");
|
||||||
|
|
||||||
|
std::optional<std::string> low = parse_stabs_identifier(input, ';');
|
||||||
|
CCC_CHECK(low.has_value(), "Failed to parse low part of range.");
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "low range value");
|
||||||
|
|
||||||
|
std::optional<std::string> high = parse_stabs_identifier(input, ';');
|
||||||
|
CCC_CHECK(high.has_value(), "Failed to parse high part of range.");
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "high range value");
|
||||||
|
|
||||||
|
range->low = std::move(*low);
|
||||||
|
range->high = std::move(*high);
|
||||||
|
|
||||||
|
out_type = std::move(range);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::STRUCT: { // s
|
||||||
|
auto struct_type = std::make_unique<StabsStructType>(type_number);
|
||||||
|
STABS_DEBUG_PRINTF("struct {\n");
|
||||||
|
|
||||||
|
std::optional<s64> struct_size = parse_number_s64(input);
|
||||||
|
CCC_CHECK(struct_size.has_value(), "Failed to parse struct size.");
|
||||||
|
struct_type->size = *struct_size;
|
||||||
|
|
||||||
|
if(*input == '!') {
|
||||||
|
input++;
|
||||||
|
std::optional<s32> base_class_count = parse_number_s32(input);
|
||||||
|
CCC_CHECK(base_class_count.has_value(), "Failed to parse base class count.");
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "base class section");
|
||||||
|
|
||||||
|
for(s64 i = 0; i < *base_class_count; i++) {
|
||||||
|
StabsStructOrUnionType::BaseClass base_class;
|
||||||
|
|
||||||
|
char is_virtual = *(input++);
|
||||||
|
switch(is_virtual) {
|
||||||
|
case '0': base_class.is_virtual = false; break;
|
||||||
|
case '1': base_class.is_virtual = true; break;
|
||||||
|
default: return CCC_FAILURE("Failed to parse base class (virtual character).");
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<StabsStructOrUnionType::Visibility> visibility = parse_visibility_character(input);
|
||||||
|
CCC_RETURN_IF_ERROR(visibility);
|
||||||
|
base_class.visibility = *visibility;
|
||||||
|
|
||||||
|
std::optional<s32> offset = parse_number_s32(input);
|
||||||
|
CCC_CHECK(offset.has_value(), "Failed to parse base class offset.");
|
||||||
|
base_class.offset = (s32) *offset;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "base class section");
|
||||||
|
|
||||||
|
auto base_class_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(base_class_type);
|
||||||
|
base_class.type = std::move(*base_class_type);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "base class section");
|
||||||
|
struct_type->base_classes.emplace_back(std::move(base_class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fields = parse_field_list(input);
|
||||||
|
CCC_RETURN_IF_ERROR(fields);
|
||||||
|
struct_type->fields = std::move(*fields);
|
||||||
|
|
||||||
|
auto member_functions = parse_member_functions(input);
|
||||||
|
CCC_RETURN_IF_ERROR(member_functions);
|
||||||
|
struct_type->member_functions = std::move(*member_functions);
|
||||||
|
|
||||||
|
STABS_DEBUG_PRINTF("}\n");
|
||||||
|
|
||||||
|
out_type = std::move(struct_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::UNION: { // u
|
||||||
|
auto union_type = std::make_unique<StabsUnionType>(type_number);
|
||||||
|
STABS_DEBUG_PRINTF("union {\n");
|
||||||
|
|
||||||
|
std::optional<s64> union_size = parse_number_s64(input);
|
||||||
|
CCC_CHECK(union_size.has_value(), "Failed to parse struct size.");
|
||||||
|
union_type->size = *union_size;
|
||||||
|
|
||||||
|
auto fields = parse_field_list(input);
|
||||||
|
CCC_RETURN_IF_ERROR(fields);
|
||||||
|
union_type->fields = std::move(*fields);
|
||||||
|
|
||||||
|
auto member_functions = parse_member_functions(input);
|
||||||
|
CCC_RETURN_IF_ERROR(member_functions);
|
||||||
|
union_type->member_functions = std::move(*member_functions);
|
||||||
|
|
||||||
|
STABS_DEBUG_PRINTF("}\n");
|
||||||
|
|
||||||
|
out_type = std::move(union_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::CROSS_REFERENCE: { // x
|
||||||
|
auto cross_reference = std::make_unique<StabsCrossReferenceType>(type_number);
|
||||||
|
|
||||||
|
char cross_reference_type = *(input++);
|
||||||
|
CCC_CHECK(cross_reference_type != '\0', "Failed to parse cross reference type.");
|
||||||
|
|
||||||
|
switch(cross_reference_type) {
|
||||||
|
case 'e': cross_reference->type = ast::ForwardDeclaredType::ENUM; break;
|
||||||
|
case 's': cross_reference->type = ast::ForwardDeclaredType::STRUCT; break;
|
||||||
|
case 'u': cross_reference->type = ast::ForwardDeclaredType::UNION; break;
|
||||||
|
default:
|
||||||
|
return CCC_FAILURE("Invalid cross reference type '%c'.", cross_reference->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::string> identifier = parse_dodgy_stabs_identifier(input, ':');
|
||||||
|
CCC_RETURN_IF_ERROR(identifier);
|
||||||
|
cross_reference->identifier = std::move(*identifier);
|
||||||
|
|
||||||
|
cross_reference->name = cross_reference->identifier;
|
||||||
|
CCC_EXPECT_CHAR(input, ':', "cross reference");
|
||||||
|
|
||||||
|
out_type = std::move(cross_reference);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::FLOATING_POINT_BUILTIN: { // R
|
||||||
|
auto fp_builtin = std::make_unique<StabsFloatingPointBuiltInType>(type_number);
|
||||||
|
|
||||||
|
std::optional<s32> fpclass = parse_number_s32(input);
|
||||||
|
CCC_CHECK(fpclass.has_value(), "Failed to parse floating point built-in class.");
|
||||||
|
fp_builtin->fpclass = *fpclass;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "floating point builtin");
|
||||||
|
|
||||||
|
std::optional<s32> bytes = parse_number_s32(input);
|
||||||
|
CCC_CHECK(bytes.has_value(), "Failed to parse floating point built-in.");
|
||||||
|
fp_builtin->bytes = *bytes;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "floating point builtin");
|
||||||
|
|
||||||
|
std::optional<s32> value = parse_number_s32(input);
|
||||||
|
CCC_CHECK(value.has_value(), "Failed to parse floating point built-in.");
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "floating point builtin");
|
||||||
|
|
||||||
|
out_type = std::move(fp_builtin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::METHOD: { // #
|
||||||
|
auto method = std::make_unique<StabsMethodType>(type_number);
|
||||||
|
|
||||||
|
if(*input == '#') {
|
||||||
|
input++;
|
||||||
|
|
||||||
|
auto return_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(return_type);
|
||||||
|
method->return_type = std::move(*return_type);
|
||||||
|
|
||||||
|
if(*input == ';') {
|
||||||
|
input++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto class_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(class_type);
|
||||||
|
method->class_type = std::move(*class_type);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "method");
|
||||||
|
|
||||||
|
auto return_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(return_type);
|
||||||
|
method->return_type = std::move(*return_type);
|
||||||
|
|
||||||
|
while(*input != '\0') {
|
||||||
|
if(*input == ';') {
|
||||||
|
input++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "method");
|
||||||
|
|
||||||
|
auto parameter_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(parameter_type);
|
||||||
|
method->parameter_types.emplace_back(std::move(*parameter_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out_type = std::move(method);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::REFERENCE: { // &
|
||||||
|
auto reference = std::make_unique<StabsReferenceType>(type_number);
|
||||||
|
|
||||||
|
auto value_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(value_type);
|
||||||
|
reference->value_type = std::move(*value_type);
|
||||||
|
|
||||||
|
out_type = std::move(reference);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::POINTER: { // *
|
||||||
|
auto pointer = std::make_unique<StabsPointerType>(type_number);
|
||||||
|
|
||||||
|
auto value_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(value_type);
|
||||||
|
pointer->value_type = std::move(*value_type);
|
||||||
|
|
||||||
|
out_type = std::move(pointer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::TYPE_ATTRIBUTE: { // @
|
||||||
|
if((*input >= '0' && *input <= '9') || *input == '(') {
|
||||||
|
auto member_pointer = std::make_unique<StabsPointerToDataMemberType>(type_number);
|
||||||
|
|
||||||
|
auto class_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(class_type);
|
||||||
|
member_pointer->class_type = std::move(*class_type);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "pointer to non-static data member");
|
||||||
|
|
||||||
|
auto member_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(member_type);
|
||||||
|
member_pointer->member_type = std::move(*member_type);
|
||||||
|
|
||||||
|
out_type = std::move(member_pointer);
|
||||||
|
} else {
|
||||||
|
auto type_attribute = std::make_unique<StabsSizeTypeAttributeType>(type_number);
|
||||||
|
CCC_CHECK(*input == 's', "Weird value following '@' type descriptor.");
|
||||||
|
input++;
|
||||||
|
|
||||||
|
std::optional<s64> size_bits = parse_number_s64(input);
|
||||||
|
CCC_CHECK(size_bits.has_value(), "Failed to parse type attribute.")
|
||||||
|
type_attribute->size_bits = *size_bits;
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "type attribute");
|
||||||
|
|
||||||
|
auto type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
type_attribute->type = std::move(*type);
|
||||||
|
|
||||||
|
out_type = std::move(type_attribute);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::BUILTIN: { // -
|
||||||
|
auto built_in = std::make_unique<StabsBuiltInType>(type_number);
|
||||||
|
|
||||||
|
std::optional<s64> type_id = parse_number_s64(input);
|
||||||
|
CCC_CHECK(type_id.has_value(), "Failed to parse built-in.");
|
||||||
|
built_in->type_id = *type_id;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "builtin");
|
||||||
|
|
||||||
|
out_type = std::move(built_in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return CCC_FAILURE(
|
||||||
|
"Invalid type descriptor '%c' (%02x).",
|
||||||
|
(u32) descriptor, (u32) descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<std::vector<StabsStructOrUnionType::Field>> parse_field_list(const char*& input)
|
||||||
|
{
|
||||||
|
std::vector<StabsStructOrUnionType::Field> fields;
|
||||||
|
|
||||||
|
while(*input != '\0') {
|
||||||
|
if(*input == ';') {
|
||||||
|
input++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* before_field = input;
|
||||||
|
StabsStructOrUnionType::Field field;
|
||||||
|
|
||||||
|
Result<std::string> name = parse_dodgy_stabs_identifier(input, ':');
|
||||||
|
CCC_RETURN_IF_ERROR(name);
|
||||||
|
field.name = std::move(*name);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ':', "identifier");
|
||||||
|
if(*input == '/') {
|
||||||
|
input++;
|
||||||
|
|
||||||
|
Result<StabsStructOrUnionType::Visibility> visibility = parse_visibility_character(input);
|
||||||
|
CCC_RETURN_IF_ERROR(visibility);
|
||||||
|
field.visibility = *visibility;
|
||||||
|
}
|
||||||
|
if(*input == ':') {
|
||||||
|
input = before_field;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
field.type = std::move(*type);
|
||||||
|
|
||||||
|
if(field.name.size() >= 1 && field.name[0] == '$') {
|
||||||
|
// Virtual function table pointers and virtual base class pointers.
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "field type");
|
||||||
|
|
||||||
|
std::optional<s32> offset_bits = parse_number_s32(input);
|
||||||
|
CCC_CHECK(offset_bits.has_value(), "Failed to parse field offset.");
|
||||||
|
field.offset_bits = *offset_bits;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "field offset");
|
||||||
|
} else if(*input == ':') {
|
||||||
|
// Static fields.
|
||||||
|
input++;
|
||||||
|
field.is_static = true;
|
||||||
|
|
||||||
|
std::optional<std::string> type_name = parse_stabs_identifier(input, ';');
|
||||||
|
CCC_CHECK(type_name.has_value(), "Failed to parse static field type name.");
|
||||||
|
|
||||||
|
field.type_name = std::move(*type_name);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "identifier");
|
||||||
|
} else if(*input == ',') {
|
||||||
|
// Normal fields.
|
||||||
|
input++;
|
||||||
|
|
||||||
|
std::optional<s32> offset_bits = parse_number_s32(input);
|
||||||
|
CCC_CHECK(offset_bits.has_value(), "Failed to parse field offset.");
|
||||||
|
field.offset_bits = *offset_bits;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ',', "field offset");
|
||||||
|
|
||||||
|
std::optional<s32> size_bits = parse_number_s32(input);
|
||||||
|
CCC_CHECK(size_bits.has_value(), "Failed to parse field size.");
|
||||||
|
field.size_bits = *size_bits;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "field size");
|
||||||
|
} else {
|
||||||
|
return CCC_FAILURE("Expected ':' or ',', got '%c' (%hhx).", *input, *input);
|
||||||
|
}
|
||||||
|
|
||||||
|
STABS_DEBUG(print_field(field);)
|
||||||
|
|
||||||
|
fields.emplace_back(std::move(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<std::vector<StabsStructOrUnionType::MemberFunctionSet>> parse_member_functions(const char*& input)
|
||||||
|
{
|
||||||
|
// Check for if the next character is from an enclosing field list. If this
|
||||||
|
// is the case, the next character will be ',' for normal fields and ':' for
|
||||||
|
// static fields (see above).
|
||||||
|
if(*input == ',' || *input == ':') {
|
||||||
|
return std::vector<StabsStructOrUnionType::MemberFunctionSet>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<StabsStructOrUnionType::MemberFunctionSet> member_functions;
|
||||||
|
while(*input != '\0') {
|
||||||
|
if(*input == ';') {
|
||||||
|
input++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
StabsStructOrUnionType::MemberFunctionSet member_function_set;
|
||||||
|
|
||||||
|
std::optional<std::string> name = parse_stabs_identifier(input, ':');
|
||||||
|
CCC_CHECK(name.has_value(), "Failed to parse member function name.");
|
||||||
|
member_function_set.name = std::move(*name);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ':', "member function");
|
||||||
|
CCC_EXPECT_CHAR(input, ':', "member function");
|
||||||
|
while(*input != '\0') {
|
||||||
|
if(*input == ';') {
|
||||||
|
input++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
StabsStructOrUnionType::MemberFunction function;
|
||||||
|
|
||||||
|
auto type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(type);
|
||||||
|
function.type = std::move(*type);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ':', "member function");
|
||||||
|
std::optional<std::string> identifier = parse_stabs_identifier(input, ';');
|
||||||
|
CCC_CHECK(identifier.has_value(), "Invalid member function identifier.");
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "member function");
|
||||||
|
|
||||||
|
Result<StabsStructOrUnionType::Visibility> visibility = parse_visibility_character(input);
|
||||||
|
CCC_RETURN_IF_ERROR(visibility);
|
||||||
|
function.visibility = *visibility;
|
||||||
|
|
||||||
|
char modifiers = *(input++);
|
||||||
|
CCC_CHECK(modifiers != '\0', "Failed to parse member function modifiers.");
|
||||||
|
switch(modifiers) {
|
||||||
|
case 'A':
|
||||||
|
function.is_const = false;
|
||||||
|
function.is_volatile = false;
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
function.is_const = true;
|
||||||
|
function.is_volatile = false;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
function.is_const = false;
|
||||||
|
function.is_volatile = true;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
function.is_const = true;
|
||||||
|
function.is_volatile = true;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
case '.':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return CCC_FAILURE("Invalid member function modifiers.");
|
||||||
|
}
|
||||||
|
|
||||||
|
char flag = *(input++);
|
||||||
|
CCC_CHECK(flag != '\0', "Failed to parse member function type.");
|
||||||
|
switch(flag) {
|
||||||
|
case '.': { // normal member function
|
||||||
|
function.modifier = ast::MemberFunctionModifier::NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '?': { // static member function
|
||||||
|
function.modifier = ast::MemberFunctionModifier::STATIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '*': { // virtual member function
|
||||||
|
std::optional<s32> vtable_index = parse_number_s32(input);
|
||||||
|
CCC_CHECK(vtable_index.has_value(), "Failed to parse vtable index.");
|
||||||
|
function.vtable_index = *vtable_index;
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "virtual member function");
|
||||||
|
|
||||||
|
auto virtual_type = parse_stabs_type(input);
|
||||||
|
CCC_RETURN_IF_ERROR(virtual_type);
|
||||||
|
function.virtual_type = std::move(*virtual_type);
|
||||||
|
|
||||||
|
CCC_EXPECT_CHAR(input, ';', "virtual member function");
|
||||||
|
function.modifier = ast::MemberFunctionModifier::VIRTUAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return CCC_FAILURE("Invalid member function type.");
|
||||||
|
}
|
||||||
|
member_function_set.overloads.emplace_back(std::move(function));
|
||||||
|
}
|
||||||
|
STABS_DEBUG_PRINTF("member func: %s\n", member_function_set.name.c_str());
|
||||||
|
member_functions.emplace_back(std::move(member_function_set));
|
||||||
|
}
|
||||||
|
return member_functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<StabsStructOrUnionType::Visibility> parse_visibility_character(const char*& input)
|
||||||
|
{
|
||||||
|
char visibility = *(input++);
|
||||||
|
switch(visibility) {
|
||||||
|
case '0': return StabsStructOrUnionType::Visibility::PRIVATE;
|
||||||
|
case '1': return StabsStructOrUnionType::Visibility::PROTECTED;
|
||||||
|
case '2': return StabsStructOrUnionType::Visibility::PUBLIC;
|
||||||
|
case '9': return StabsStructOrUnionType::Visibility::PUBLIC_OPTIMIZED_OUT;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CCC_FAILURE("Failed to parse visibility character.");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<s32> parse_number_s32(const char*& input)
|
||||||
|
{
|
||||||
|
char* end;
|
||||||
|
s64 value = strtoll(input, &end, 10);
|
||||||
|
if(end == input) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
input = end;
|
||||||
|
return (s32) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<s64> parse_number_s64(const char*& input)
|
||||||
|
{
|
||||||
|
char* end;
|
||||||
|
s64 value = strtoll(input, &end, 10);
|
||||||
|
if(end == input) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
input = end;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> parse_stabs_identifier(const char*& input, char terminator)
|
||||||
|
{
|
||||||
|
const char* begin = input;
|
||||||
|
for(; *input != '\0'; input++) {
|
||||||
|
if(*input == terminator) {
|
||||||
|
return std::string(begin, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The complexity here is because the input may contain an unescaped namespace
|
||||||
|
// separator '::' even if the field terminator is supposed to be a colon, as
|
||||||
|
// well as the raw contents of character literals. See test/ccc/stabs_tests.cpp
|
||||||
|
// for some examples.
|
||||||
|
Result<std::string> parse_dodgy_stabs_identifier(const char*& input, char terminator)
|
||||||
|
{
|
||||||
|
const char* begin = input;
|
||||||
|
s32 template_depth = 0;
|
||||||
|
|
||||||
|
for(; *input != '\0'; input++) {
|
||||||
|
// Skip past character literals.
|
||||||
|
if(*input == '\'') {
|
||||||
|
input++;
|
||||||
|
if(*input == '\'') {
|
||||||
|
input++; // Handle character literals containing a single quote.
|
||||||
|
}
|
||||||
|
while(*input != '\'' && *input != '\0') {
|
||||||
|
input++;
|
||||||
|
}
|
||||||
|
if(*input == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
input++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep track of the template depth so we know when to expect the
|
||||||
|
// terminator character.
|
||||||
|
if(*input == '<') {
|
||||||
|
template_depth++;
|
||||||
|
}
|
||||||
|
if(*input == '>') {
|
||||||
|
template_depth--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*input == terminator && template_depth == 0) {
|
||||||
|
return std::string(begin, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CCC_FAILURE(STAB_TRUNCATED_ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
STABS_DEBUG(
|
||||||
|
|
||||||
|
static void print_field(const StabsStructOrUnionType::Field& field)
|
||||||
|
{
|
||||||
|
printf("\t%04x %04x %04x %04x %s\n", field.offset_bits / 8, field.size_bits / 8, field.offset_bits, field.size_bits, field.name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
const char* stabs_field_visibility_to_string(StabsStructOrUnionType::Visibility visibility)
|
||||||
|
{
|
||||||
|
switch(visibility) {
|
||||||
|
case StabsStructOrUnionType::Visibility::PRIVATE: return "private";
|
||||||
|
case StabsStructOrUnionType::Visibility::PROTECTED: return "protected";
|
||||||
|
case StabsStructOrUnionType::Visibility::PUBLIC: return "public";
|
||||||
|
case StabsStructOrUnionType::Visibility::PUBLIC_OPTIMIZED_OUT: return "public_optimizedout";
|
||||||
|
default: return "none";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,379 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ast.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
enum class StabsSymbolDescriptor : u8 {
|
||||||
|
LOCAL_VARIABLE = '_',
|
||||||
|
REFERENCE_PARAMETER_A = 'a',
|
||||||
|
LOCAL_FUNCTION = 'f',
|
||||||
|
GLOBAL_FUNCTION = 'F',
|
||||||
|
GLOBAL_VARIABLE = 'G',
|
||||||
|
REGISTER_PARAMETER = 'P',
|
||||||
|
VALUE_PARAMETER = 'p',
|
||||||
|
REGISTER_VARIABLE = 'r',
|
||||||
|
STATIC_GLOBAL_VARIABLE = 'S',
|
||||||
|
TYPE_NAME = 't',
|
||||||
|
ENUM_STRUCT_OR_TYPE_TAG = 'T',
|
||||||
|
STATIC_LOCAL_VARIABLE = 'V',
|
||||||
|
REFERENCE_PARAMETER_V = 'v'
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsType;
|
||||||
|
|
||||||
|
struct StabsSymbol {
|
||||||
|
StabsSymbolDescriptor descriptor;
|
||||||
|
std::string name;
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<StabsSymbol> parse_stabs_symbol(const char*& input);
|
||||||
|
|
||||||
|
enum class StabsTypeDescriptor : u8 {
|
||||||
|
TYPE_REFERENCE = 0xef, // '0'..'9','('
|
||||||
|
ARRAY = 'a',
|
||||||
|
ENUM = 'e',
|
||||||
|
FUNCTION = 'f',
|
||||||
|
CONST_QUALIFIER = 'k',
|
||||||
|
RANGE = 'r',
|
||||||
|
STRUCT = 's',
|
||||||
|
UNION = 'u',
|
||||||
|
CROSS_REFERENCE = 'x',
|
||||||
|
VOLATILE_QUALIFIER = 'B',
|
||||||
|
FLOATING_POINT_BUILTIN = 'R',
|
||||||
|
METHOD = '#',
|
||||||
|
REFERENCE = '&',
|
||||||
|
POINTER = '*',
|
||||||
|
TYPE_ATTRIBUTE = '@',
|
||||||
|
POINTER_TO_DATA_MEMBER = 0xee, // also '@'
|
||||||
|
BUILTIN = '-'
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsBaseClass;
|
||||||
|
struct StabsField;
|
||||||
|
struct StabsMemberFunctionSet;
|
||||||
|
|
||||||
|
// e.g. for "123=*456" 123 would be the type_number, the type descriptor would
|
||||||
|
// be of type POINTER and StabsPointerType::value_type would point to a type
|
||||||
|
// with type_number = 456.
|
||||||
|
struct StabsType {
|
||||||
|
StabsTypeNumber type_number;
|
||||||
|
// The name field is only populated for root types and cross references.
|
||||||
|
std::optional<std::string> name;
|
||||||
|
bool is_typedef = false;
|
||||||
|
bool is_root = false;
|
||||||
|
std::optional<StabsTypeDescriptor> descriptor;
|
||||||
|
|
||||||
|
StabsType(StabsTypeNumber n) : type_number(n) {}
|
||||||
|
StabsType(StabsTypeDescriptor d) : descriptor(d) {}
|
||||||
|
StabsType(StabsTypeNumber n, StabsTypeDescriptor d) : type_number(n), descriptor(d) {}
|
||||||
|
virtual ~StabsType() {}
|
||||||
|
|
||||||
|
template <typename SubType>
|
||||||
|
SubType& as()
|
||||||
|
{
|
||||||
|
CCC_ASSERT(descriptor == SubType::DESCRIPTOR);
|
||||||
|
return *static_cast<SubType*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename SubType>
|
||||||
|
const SubType& as() const
|
||||||
|
{
|
||||||
|
CCC_ASSERT(descriptor == SubType::DESCRIPTOR);
|
||||||
|
return *static_cast<const SubType*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const
|
||||||
|
{
|
||||||
|
if(type_number.valid() && descriptor.has_value()) {
|
||||||
|
output.emplace(type_number, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsTypeReferenceType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
|
||||||
|
StabsTypeReferenceType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::TYPE_REFERENCE;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsArrayType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> index_type;
|
||||||
|
std::unique_ptr<StabsType> element_type;
|
||||||
|
|
||||||
|
StabsArrayType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::ARRAY;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
index_type->enumerate_numbered_types(output);
|
||||||
|
element_type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsEnumType : StabsType {
|
||||||
|
std::vector<std::pair<s32, std::string>> fields;
|
||||||
|
|
||||||
|
StabsEnumType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::ENUM;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsFunctionType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> return_type;
|
||||||
|
|
||||||
|
StabsFunctionType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::FUNCTION;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
return_type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsVolatileQualifierType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
|
||||||
|
StabsVolatileQualifierType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::VOLATILE_QUALIFIER;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsConstQualifierType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
|
||||||
|
StabsConstQualifierType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::CONST_QUALIFIER;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsRangeType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
std::string low;
|
||||||
|
std::string high; // Some compilers wrote out a wrapped around value here for zero (or variable?) length arrays.
|
||||||
|
|
||||||
|
StabsRangeType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::RANGE;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsStructOrUnionType : StabsType {
|
||||||
|
enum class Visibility : u8 {
|
||||||
|
NONE,
|
||||||
|
PRIVATE,
|
||||||
|
PROTECTED,
|
||||||
|
PUBLIC,
|
||||||
|
PUBLIC_OPTIMIZED_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BaseClass {
|
||||||
|
bool is_virtual;
|
||||||
|
Visibility visibility;
|
||||||
|
s32 offset = -1;
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Field {
|
||||||
|
std::string name;
|
||||||
|
Visibility visibility = Visibility::NONE;
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
bool is_static = false;
|
||||||
|
s32 offset_bits = 0;
|
||||||
|
s32 size_bits = 0;
|
||||||
|
std::string type_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MemberFunction {
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
std::unique_ptr<StabsType> virtual_type;
|
||||||
|
Visibility visibility;
|
||||||
|
bool is_const = false;
|
||||||
|
bool is_volatile = false;
|
||||||
|
ast::MemberFunctionModifier modifier = ast::MemberFunctionModifier::NONE;
|
||||||
|
s32 vtable_index = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MemberFunctionSet {
|
||||||
|
std::string name;
|
||||||
|
std::vector<MemberFunction> overloads;
|
||||||
|
};
|
||||||
|
|
||||||
|
s64 size = -1;
|
||||||
|
std::vector<BaseClass> base_classes;
|
||||||
|
std::vector<Field> fields;
|
||||||
|
std::vector<MemberFunctionSet> member_functions;
|
||||||
|
std::unique_ptr<StabsType> first_base_class;
|
||||||
|
|
||||||
|
StabsStructOrUnionType(StabsTypeNumber n, StabsTypeDescriptor d) : StabsType(n, d) {}
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
for(const BaseClass& base_class : base_classes) {
|
||||||
|
base_class.type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
for(const Field& field : fields) {
|
||||||
|
field.type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
for(const MemberFunctionSet& member_function_set : member_functions) {
|
||||||
|
for(const MemberFunction& member_function : member_function_set.overloads) {
|
||||||
|
member_function.type->enumerate_numbered_types(output);
|
||||||
|
if(member_function.virtual_type.get()) {
|
||||||
|
member_function.virtual_type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(first_base_class.get()) {
|
||||||
|
first_base_class->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsStructType : StabsStructOrUnionType {
|
||||||
|
StabsStructType(StabsTypeNumber n) : StabsStructOrUnionType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::STRUCT;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsUnionType : StabsStructOrUnionType {
|
||||||
|
StabsUnionType(StabsTypeNumber n) : StabsStructOrUnionType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::UNION;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct StabsCrossReferenceType : StabsType {
|
||||||
|
ast::ForwardDeclaredType type;
|
||||||
|
std::string identifier;
|
||||||
|
|
||||||
|
StabsCrossReferenceType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::CROSS_REFERENCE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsFloatingPointBuiltInType : StabsType {
|
||||||
|
s32 fpclass = -1;
|
||||||
|
s32 bytes = -1;
|
||||||
|
|
||||||
|
StabsFloatingPointBuiltInType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::FLOATING_POINT_BUILTIN;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsMethodType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> return_type;
|
||||||
|
std::optional<std::unique_ptr<StabsType>> class_type;
|
||||||
|
std::vector<std::unique_ptr<StabsType>> parameter_types;
|
||||||
|
|
||||||
|
StabsMethodType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::METHOD;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
return_type->enumerate_numbered_types(output);
|
||||||
|
if(class_type.has_value()) {
|
||||||
|
(*class_type)->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
for(const std::unique_ptr<StabsType>& parameter_type : parameter_types) {
|
||||||
|
parameter_type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsReferenceType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> value_type;
|
||||||
|
|
||||||
|
StabsReferenceType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::REFERENCE;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
value_type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsPointerType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> value_type;
|
||||||
|
|
||||||
|
StabsPointerType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::POINTER;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
value_type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsSizeTypeAttributeType : StabsType {
|
||||||
|
s64 size_bits = -1;
|
||||||
|
std::unique_ptr<StabsType> type;
|
||||||
|
|
||||||
|
StabsSizeTypeAttributeType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::TYPE_ATTRIBUTE;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsPointerToDataMemberType : StabsType {
|
||||||
|
std::unique_ptr<StabsType> class_type;
|
||||||
|
std::unique_ptr<StabsType> member_type;
|
||||||
|
|
||||||
|
StabsPointerToDataMemberType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::POINTER_TO_DATA_MEMBER;
|
||||||
|
|
||||||
|
void enumerate_numbered_types(std::map<StabsTypeNumber, const StabsType*>& output) const override
|
||||||
|
{
|
||||||
|
StabsType::enumerate_numbered_types(output);
|
||||||
|
class_type->enumerate_numbered_types(output);
|
||||||
|
member_type->enumerate_numbered_types(output);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StabsBuiltInType : StabsType {
|
||||||
|
s64 type_id = -1;
|
||||||
|
|
||||||
|
StabsBuiltInType(StabsTypeNumber n) : StabsType(n, DESCRIPTOR) {}
|
||||||
|
static const constexpr StabsTypeDescriptor DESCRIPTOR = StabsTypeDescriptor::BUILTIN;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char* STAB_TRUNCATED_ERROR_MESSAGE;
|
||||||
|
|
||||||
|
Result<std::unique_ptr<StabsType>> parse_top_level_stabs_type(const char*& input);
|
||||||
|
std::optional<s32> parse_number_s32(const char*& input);
|
||||||
|
std::optional<s64> parse_number_s64(const char*& input);
|
||||||
|
std::optional<std::string> parse_stabs_identifier(const char*& input, char terminator);
|
||||||
|
Result<std::string> parse_dodgy_stabs_identifier(const char*& input, char terminator);
|
||||||
|
const char* stabs_field_visibility_to_string(StabsStructOrUnionType::Visibility visibility);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,834 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "stabs_to_ast.h"
|
||||||
|
|
||||||
|
#include "importer_flags.h"
|
||||||
|
|
||||||
|
#define AST_DEBUG(...) //__VA_ARGS__
|
||||||
|
#define AST_DEBUG_PRINTF(...) AST_DEBUG(printf(__VA_ARGS__);)
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
struct MemberFunctionInfo {
|
||||||
|
std::string name;
|
||||||
|
bool is_constructor_or_destructor = false;
|
||||||
|
bool is_special_member_function = false;
|
||||||
|
bool is_operator_member_function = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool is_void_like(const StabsType& type);
|
||||||
|
static Result<ast::BuiltInClass> classify_range(const StabsRangeType& type);
|
||||||
|
static Result<std::unique_ptr<ast::Node>> field_to_ast(
|
||||||
|
const StabsStructOrUnionType::Field& field,
|
||||||
|
const StabsType& enclosing_struct,
|
||||||
|
const StabsToAstState& state,
|
||||||
|
s32 depth);
|
||||||
|
static Result<bool> detect_bitfield(const StabsStructOrUnionType::Field& field, const StabsToAstState& state);
|
||||||
|
static Result<std::vector<std::unique_ptr<ast::Node>>> member_functions_to_ast(
|
||||||
|
const StabsStructOrUnionType& type, const StabsToAstState& state, s32 depth);
|
||||||
|
static MemberFunctionInfo check_member_function(
|
||||||
|
const std::string& mangled_name,
|
||||||
|
std::string_view type_name_no_template_args,
|
||||||
|
const DemanglerFunctions& demangler,
|
||||||
|
u32 importer_flags);
|
||||||
|
|
||||||
|
Result<std::unique_ptr<ast::Node>> stabs_type_to_ast(
|
||||||
|
const StabsType& type,
|
||||||
|
const StabsType* enclosing_struct,
|
||||||
|
const StabsToAstState& state,
|
||||||
|
s32 depth,
|
||||||
|
bool substitute_type_name,
|
||||||
|
bool force_substitute)
|
||||||
|
{
|
||||||
|
AST_DEBUG_PRINTF("%-*stype desc=%hhx '%c' num=(%d,%d) name=%s\n",
|
||||||
|
depth * 4, "",
|
||||||
|
type.descriptor.has_value() ? (u8) *type.descriptor : 'X',
|
||||||
|
(type.descriptor.has_value() && isprint((u8) *type.descriptor)) ? (u8) *type.descriptor : '!',
|
||||||
|
type.type_number.file, type.type_number.type,
|
||||||
|
type.name.has_value() ? type.name->c_str() : "");
|
||||||
|
|
||||||
|
if(depth > 200) {
|
||||||
|
const char* error_message = "Call depth greater than 200 in stabs_type_to_ast, probably infinite recursion.";
|
||||||
|
if(state.importer_flags & STRICT_PARSING) {
|
||||||
|
return CCC_FAILURE(error_message);
|
||||||
|
} else {
|
||||||
|
CCC_WARN(error_message);
|
||||||
|
|
||||||
|
auto error = std::make_unique<ast::Error>();
|
||||||
|
error->message = error_message;
|
||||||
|
return std::unique_ptr<ast::Node>(std::move(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This makes sure that types are replaced with their type name in cases
|
||||||
|
// where that would be more appropriate.
|
||||||
|
if(type.name.has_value()) {
|
||||||
|
bool try_substitute = depth > 0 && (type.is_root
|
||||||
|
|| type.descriptor == StabsTypeDescriptor::RANGE
|
||||||
|
|| type.descriptor == StabsTypeDescriptor::BUILTIN);
|
||||||
|
// GCC emits anonymous enums with a name of " " since apparently some
|
||||||
|
// debuggers can't handle zero-length names.
|
||||||
|
bool is_name_empty = type.name == "" || type.name == " ";
|
||||||
|
// Cross references will be handled below.
|
||||||
|
bool is_cross_reference = type.descriptor == StabsTypeDescriptor::CROSS_REFERENCE;
|
||||||
|
bool is_void = is_void_like(type);
|
||||||
|
if((substitute_type_name || try_substitute) && !is_name_empty && !is_cross_reference && !is_void) {
|
||||||
|
auto type_name = std::make_unique<ast::TypeName>();
|
||||||
|
type_name->source = ast::TypeNameSource::REFERENCE;
|
||||||
|
type_name->unresolved_stabs = std::make_unique<ast::TypeName::UnresolvedStabs>();
|
||||||
|
type_name->unresolved_stabs->type_name = *type.name;
|
||||||
|
type_name->unresolved_stabs->referenced_file_handle = state.file_handle;
|
||||||
|
type_name->unresolved_stabs->stabs_type_number = type.type_number;
|
||||||
|
return std::unique_ptr<ast::Node>(std::move(type_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This prevents infinite recursion when an automatically generated member
|
||||||
|
// function references an unnamed type.
|
||||||
|
bool can_compare_type_numbers = type.type_number.valid() && enclosing_struct && enclosing_struct->type_number.valid();
|
||||||
|
if(force_substitute && can_compare_type_numbers && type.type_number == enclosing_struct->type_number) {
|
||||||
|
// It's probably a this parameter (or return type) for an unnamed type.
|
||||||
|
auto type_name = std::make_unique<ast::TypeName>();
|
||||||
|
type_name->source = ast::TypeNameSource::UNNAMED_THIS;
|
||||||
|
type_name->unresolved_stabs = std::make_unique<ast::TypeName::UnresolvedStabs>();
|
||||||
|
type_name->unresolved_stabs->type_name = enclosing_struct->name.has_value() ? *enclosing_struct->name : "";
|
||||||
|
type_name->unresolved_stabs->referenced_file_handle = state.file_handle;
|
||||||
|
type_name->unresolved_stabs->stabs_type_number = type.type_number;
|
||||||
|
return std::unique_ptr<ast::Node>(std::move(type_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!type.descriptor.has_value()) {
|
||||||
|
// The definition of the type has been defined previously, so we have to
|
||||||
|
// look it up by its type number.
|
||||||
|
CCC_CHECK(type.type_number.valid(), "Cannot lookup type (type is anonymous).");
|
||||||
|
auto stabs_type = state.stabs_types->find(type.type_number);
|
||||||
|
if(stabs_type == state.stabs_types->end()) {
|
||||||
|
std::string error_message = "Failed to lookup STABS type by its type number ("
|
||||||
|
+ std::to_string(type.type_number.file) + "," + std::to_string(type.type_number.type) + ").";
|
||||||
|
if(state.importer_flags & STRICT_PARSING) {
|
||||||
|
return CCC_FAILURE("%s", error_message.c_str());
|
||||||
|
} else {
|
||||||
|
CCC_WARN("%s", error_message.c_str());
|
||||||
|
std::unique_ptr<ast::Error> error = std::make_unique<ast::Error>();
|
||||||
|
error->message = std::move(error_message);
|
||||||
|
return std::unique_ptr<ast::Node>(std::move(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stabs_type_to_ast(
|
||||||
|
*stabs_type->second,
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
substitute_type_name,
|
||||||
|
force_substitute);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ast::Node> result;
|
||||||
|
|
||||||
|
switch(*type.descriptor) {
|
||||||
|
case StabsTypeDescriptor::TYPE_REFERENCE: {
|
||||||
|
const auto& stabs_type_ref = type.as<StabsTypeReferenceType>();
|
||||||
|
if(!type.type_number.valid() || !stabs_type_ref.type->type_number.valid() || stabs_type_ref.type->type_number != type.type_number) {
|
||||||
|
auto node = stabs_type_to_ast(
|
||||||
|
*stabs_type_ref.type,
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
substitute_type_name,
|
||||||
|
force_substitute);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
result = std::move(*node);
|
||||||
|
} else {
|
||||||
|
// I still don't know why in STABS void is a reference to
|
||||||
|
// itself, maybe because I'm not a philosopher.
|
||||||
|
auto builtin = std::make_unique<ast::BuiltIn>();
|
||||||
|
builtin->bclass = ast::BuiltInClass::VOID_TYPE;
|
||||||
|
result = std::move(builtin);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::ARRAY: {
|
||||||
|
auto array = std::make_unique<ast::Array>();
|
||||||
|
const auto& stabs_array = type.as<StabsArrayType>();
|
||||||
|
|
||||||
|
auto element_node = stabs_type_to_ast(
|
||||||
|
*stabs_array.element_type,
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
force_substitute);
|
||||||
|
CCC_RETURN_IF_ERROR(element_node);
|
||||||
|
array->element_type = std::move(*element_node);
|
||||||
|
|
||||||
|
const StabsRangeType& index = stabs_array.index_type->as<StabsRangeType>();
|
||||||
|
|
||||||
|
char* end = nullptr;
|
||||||
|
|
||||||
|
const char* low = index.low.c_str();
|
||||||
|
s64 low_value = strtoll(low, &end, 10);
|
||||||
|
CCC_CHECK(end != low, "Failed to parse low part of range as integer.");
|
||||||
|
CCC_CHECK(low_value == 0, "Invalid index type for array.");
|
||||||
|
|
||||||
|
const char* high = index.high.c_str();
|
||||||
|
s64 high_value = strtoll(high, &end, 10);
|
||||||
|
CCC_CHECK(end != high, "Failed to parse low part of range as integer.");
|
||||||
|
|
||||||
|
if(high_value == 4294967295) {
|
||||||
|
// Some compilers wrote out a wrapped around value here.
|
||||||
|
array->element_count = 0;
|
||||||
|
} else {
|
||||||
|
array->element_count = (s32) high_value + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = std::move(array);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::ENUM: {
|
||||||
|
auto inline_enum = std::make_unique<ast::Enum>();
|
||||||
|
const auto& stabs_enum = type.as<StabsEnumType>();
|
||||||
|
inline_enum->constants = stabs_enum.fields;
|
||||||
|
result = std::move(inline_enum);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::FUNCTION: {
|
||||||
|
auto function = std::make_unique<ast::Function>();
|
||||||
|
|
||||||
|
auto node = stabs_type_to_ast(
|
||||||
|
*type.as<StabsFunctionType>().return_type,
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
force_substitute);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
function->return_type = std::move(*node);
|
||||||
|
|
||||||
|
result = std::move(function);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::VOLATILE_QUALIFIER: {
|
||||||
|
const auto& volatile_qualifier = type.as<StabsVolatileQualifierType>();
|
||||||
|
|
||||||
|
auto node = stabs_type_to_ast(
|
||||||
|
*volatile_qualifier.type.get(),
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
substitute_type_name,
|
||||||
|
force_substitute);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
result = std::move(*node);
|
||||||
|
|
||||||
|
result->is_volatile = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::CONST_QUALIFIER: {
|
||||||
|
const auto& const_qualifier = type.as<StabsConstQualifierType>();
|
||||||
|
|
||||||
|
auto node = stabs_type_to_ast(
|
||||||
|
*const_qualifier.type.get(),
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
substitute_type_name,
|
||||||
|
force_substitute);
|
||||||
|
result = std::move(*node);
|
||||||
|
|
||||||
|
result->is_const = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::RANGE: {
|
||||||
|
auto builtin = std::make_unique<ast::BuiltIn>();
|
||||||
|
Result<ast::BuiltInClass> bclass = classify_range(type.as<StabsRangeType>());
|
||||||
|
CCC_RETURN_IF_ERROR(bclass);
|
||||||
|
builtin->bclass = *bclass;
|
||||||
|
result = std::move(builtin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::STRUCT:
|
||||||
|
case StabsTypeDescriptor::UNION: {
|
||||||
|
const StabsStructOrUnionType* stabs_struct_or_union;
|
||||||
|
if(type.descriptor == StabsTypeDescriptor::STRUCT) {
|
||||||
|
stabs_struct_or_union = &type.as<StabsStructType>();
|
||||||
|
} else {
|
||||||
|
stabs_struct_or_union = &type.as<StabsUnionType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto struct_or_union = std::make_unique<ast::StructOrUnion>();
|
||||||
|
struct_or_union->is_struct = type.descriptor == StabsTypeDescriptor::STRUCT;
|
||||||
|
struct_or_union->size_bits = (s32) stabs_struct_or_union->size * 8;
|
||||||
|
|
||||||
|
for(const StabsStructOrUnionType::BaseClass& stabs_base_class : stabs_struct_or_union->base_classes) {
|
||||||
|
auto base_class = stabs_type_to_ast(
|
||||||
|
*stabs_base_class.type,
|
||||||
|
&type,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
force_substitute);
|
||||||
|
CCC_RETURN_IF_ERROR(base_class);
|
||||||
|
|
||||||
|
(*base_class)->offset_bytes = stabs_base_class.offset;
|
||||||
|
(*base_class)->set_access_specifier(stabs_field_visibility_to_access_specifier(stabs_base_class.visibility), state.importer_flags);
|
||||||
|
|
||||||
|
if(stabs_base_class.is_virtual) {
|
||||||
|
(*base_class)->is_virtual_base_class = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct_or_union->base_classes.emplace_back(std::move(*base_class));
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_DEBUG_PRINTF("%-*s beginfields\n", depth * 4, "");
|
||||||
|
for(const StabsStructOrUnionType::Field& field : stabs_struct_or_union->fields) {
|
||||||
|
auto node = field_to_ast(field, type, state, depth);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
struct_or_union->fields.emplace_back(std::move(*node));
|
||||||
|
}
|
||||||
|
AST_DEBUG_PRINTF("%-*s endfields\n", depth * 4, "");
|
||||||
|
|
||||||
|
AST_DEBUG_PRINTF("%-*s beginmemberfuncs\n", depth * 4, "");
|
||||||
|
Result<std::vector<std::unique_ptr<ast::Node>>> member_functions =
|
||||||
|
member_functions_to_ast(*stabs_struct_or_union, state, depth);
|
||||||
|
CCC_RETURN_IF_ERROR(member_functions);
|
||||||
|
struct_or_union->member_functions = std::move(*member_functions);
|
||||||
|
AST_DEBUG_PRINTF("%-*s endmemberfuncs\n", depth * 4, "");
|
||||||
|
|
||||||
|
result = std::move(struct_or_union);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::CROSS_REFERENCE: {
|
||||||
|
const auto& cross_reference = type.as<StabsCrossReferenceType>();
|
||||||
|
auto type_name = std::make_unique<ast::TypeName>();
|
||||||
|
type_name->source = ast::TypeNameSource::CROSS_REFERENCE;
|
||||||
|
type_name->unresolved_stabs = std::make_unique<ast::TypeName::UnresolvedStabs>();
|
||||||
|
type_name->unresolved_stabs->type_name = cross_reference.identifier;
|
||||||
|
type_name->unresolved_stabs->type = cross_reference.type;
|
||||||
|
result = std::move(type_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ccc::StabsTypeDescriptor::FLOATING_POINT_BUILTIN: {
|
||||||
|
const auto& fp_builtin = type.as<StabsFloatingPointBuiltInType>();
|
||||||
|
auto builtin = std::make_unique<ast::BuiltIn>();
|
||||||
|
switch(fp_builtin.bytes) {
|
||||||
|
case 1: builtin->bclass = ast::BuiltInClass::UNSIGNED_8; break;
|
||||||
|
case 2: builtin->bclass = ast::BuiltInClass::UNSIGNED_16; break;
|
||||||
|
case 4: builtin->bclass = ast::BuiltInClass::UNSIGNED_32; break;
|
||||||
|
case 8: builtin->bclass = ast::BuiltInClass::UNSIGNED_64; break;
|
||||||
|
case 16: builtin->bclass = ast::BuiltInClass::UNSIGNED_128; break;
|
||||||
|
default: builtin->bclass = ast::BuiltInClass::UNSIGNED_8; break;
|
||||||
|
}
|
||||||
|
result = std::move(builtin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::METHOD: {
|
||||||
|
const auto& stabs_method = type.as<StabsMethodType>();
|
||||||
|
auto function = std::make_unique<ast::Function>();
|
||||||
|
|
||||||
|
auto return_node = stabs_type_to_ast(
|
||||||
|
*stabs_method.return_type.get(),
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
CCC_RETURN_IF_ERROR(return_node);
|
||||||
|
function->return_type = std::move(*return_node);
|
||||||
|
|
||||||
|
function->parameters.emplace();
|
||||||
|
for(const std::unique_ptr<StabsType>& parameter_type : stabs_method.parameter_types) {
|
||||||
|
auto parameter_node = stabs_type_to_ast(
|
||||||
|
*parameter_type,
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
CCC_RETURN_IF_ERROR(parameter_node);
|
||||||
|
function->parameters->emplace_back(std::move(*parameter_node));
|
||||||
|
}
|
||||||
|
result = std::move(function);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::POINTER: {
|
||||||
|
auto pointer = std::make_unique<ast::PointerOrReference>();
|
||||||
|
pointer->is_pointer = true;
|
||||||
|
|
||||||
|
auto value_node = stabs_type_to_ast(
|
||||||
|
*type.as<StabsPointerType>().value_type,
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
force_substitute);
|
||||||
|
CCC_RETURN_IF_ERROR(value_node);
|
||||||
|
pointer->value_type = std::move(*value_node);
|
||||||
|
|
||||||
|
result = std::move(pointer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::REFERENCE: {
|
||||||
|
auto reference = std::make_unique<ast::PointerOrReference>();
|
||||||
|
reference->is_pointer = false;
|
||||||
|
|
||||||
|
auto value_node = stabs_type_to_ast(
|
||||||
|
*type.as<StabsReferenceType>().value_type,
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
force_substitute);
|
||||||
|
CCC_RETURN_IF_ERROR(value_node);
|
||||||
|
reference->value_type = std::move(*value_node);
|
||||||
|
|
||||||
|
result = std::move(reference);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::TYPE_ATTRIBUTE: {
|
||||||
|
const auto& stabs_type_attribute = type.as<StabsSizeTypeAttributeType>();
|
||||||
|
|
||||||
|
auto node = stabs_type_to_ast(
|
||||||
|
*stabs_type_attribute.type,
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
substitute_type_name,
|
||||||
|
force_substitute);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
result = std::move(*node);
|
||||||
|
|
||||||
|
result->size_bits = (s32) stabs_type_attribute.size_bits;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::POINTER_TO_DATA_MEMBER: {
|
||||||
|
const auto& stabs_member_pointer = type.as<StabsPointerToDataMemberType>();
|
||||||
|
auto member_pointer = std::make_unique<ast::PointerToDataMember>();
|
||||||
|
|
||||||
|
auto class_node = stabs_type_to_ast(
|
||||||
|
*stabs_member_pointer.class_type.get(),
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
CCC_RETURN_IF_ERROR(class_node);
|
||||||
|
member_pointer->class_type = std::move(*class_node);
|
||||||
|
|
||||||
|
auto member_node = stabs_type_to_ast(
|
||||||
|
*stabs_member_pointer.member_type.get(),
|
||||||
|
enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
CCC_RETURN_IF_ERROR(member_node);
|
||||||
|
member_pointer->member_type = std::move(*member_node);
|
||||||
|
|
||||||
|
result = std::move(member_pointer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::BUILTIN: {
|
||||||
|
CCC_CHECK(type.as<StabsBuiltInType>().type_id == 16,
|
||||||
|
"Unknown built-in type!");
|
||||||
|
auto builtin = std::make_unique<ast::BuiltIn>();
|
||||||
|
builtin->bclass = ast::BuiltInClass::BOOL_8;
|
||||||
|
result = std::move(builtin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CCC_CHECK(result, "Result of stabs_type_to_ast call is nullptr.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_void_like(const StabsType& type)
|
||||||
|
{
|
||||||
|
// Unfortunately, a common case seems to be that various types (most
|
||||||
|
// commonly __builtin_va_list) are indistinguishable from void or void*, so
|
||||||
|
// we have to output them as a void built-in.
|
||||||
|
if(type.descriptor.has_value()) {
|
||||||
|
switch(*type.descriptor) {
|
||||||
|
case StabsTypeDescriptor::POINTER: {
|
||||||
|
return is_void_like(*type.as<StabsPointerType>().value_type.get());
|
||||||
|
}
|
||||||
|
case StabsTypeDescriptor::TYPE_REFERENCE: {
|
||||||
|
return type.as<StabsTypeReferenceType>().type->type_number == type.type_number;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<ast::BuiltInClass> classify_range(const StabsRangeType& type)
|
||||||
|
{
|
||||||
|
const char* low = type.low.c_str();
|
||||||
|
const char* high = type.high.c_str();
|
||||||
|
|
||||||
|
// Handle some special cases and values that are too large to easily store
|
||||||
|
// in a 64-bit integer.
|
||||||
|
static const struct { const char* low; const char* high; ast::BuiltInClass classification; } strings[] = {
|
||||||
|
{"4", "0", ast::BuiltInClass::FLOAT_32},
|
||||||
|
{"000000000000000000000000", "001777777777777777777777", ast::BuiltInClass::UNSIGNED_64},
|
||||||
|
{"00000000000000000000000000000000000000000000", "00000000000000000000001777777777777777777777", ast::BuiltInClass::UNSIGNED_64},
|
||||||
|
{"0000000000000", "01777777777777777777777", ast::BuiltInClass::UNSIGNED_64}, // IOP
|
||||||
|
{"0", "18446744073709551615", ast::BuiltInClass::UNSIGNED_64},
|
||||||
|
{"001000000000000000000000", "000777777777777777777777", ast::BuiltInClass::SIGNED_64},
|
||||||
|
{"00000000000000000000001000000000000000000000", "00000000000000000000000777777777777777777777", ast::BuiltInClass::SIGNED_64},
|
||||||
|
{"01000000000000000000000", "0777777777777777777777", ast::BuiltInClass::SIGNED_64}, // IOP
|
||||||
|
{"-9223372036854775808", "9223372036854775807", ast::BuiltInClass::SIGNED_64},
|
||||||
|
{"8", "0", ast::BuiltInClass::FLOAT_64},
|
||||||
|
{"00000000000000000000000000000000000000000000", "03777777777777777777777777777777777777777777", ast::BuiltInClass::UNSIGNED_128},
|
||||||
|
{"02000000000000000000000000000000000000000000", "01777777777777777777777777777777777777777777", ast::BuiltInClass::SIGNED_128},
|
||||||
|
{"000000000000000000000000", "0377777777777777777777777777777777", ast::BuiltInClass::UNQUALIFIED_128},
|
||||||
|
{"16", "0", ast::BuiltInClass::FLOAT_128},
|
||||||
|
{"0", "-1", ast::BuiltInClass::UNQUALIFIED_128} // Old homebrew toolchain
|
||||||
|
};
|
||||||
|
|
||||||
|
for(const auto& range : strings) {
|
||||||
|
if(strcmp(range.low, low) == 0 && strcmp(range.high, high) == 0) {
|
||||||
|
return range.classification;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For smaller values we actually parse the bounds as integers.
|
||||||
|
char* end = nullptr;
|
||||||
|
s64 low_value = strtoll(type.low.c_str(), &end, low[0] == '0' ? 8 : 10);
|
||||||
|
CCC_CHECK(end != low, "Failed to parse low part of range as integer.");
|
||||||
|
s64 high_value = strtoll(type.high.c_str(), &end, high[0] == '0' ? 8 : 10);
|
||||||
|
CCC_CHECK(end != high, "Failed to parse high part of range as integer.");
|
||||||
|
|
||||||
|
static const struct { s64 low; s64 high; ast::BuiltInClass classification; } integers[] = {
|
||||||
|
{0, 255, ast::BuiltInClass::UNSIGNED_8},
|
||||||
|
{-128, 127, ast::BuiltInClass::SIGNED_8},
|
||||||
|
{0, 127, ast::BuiltInClass::UNQUALIFIED_8},
|
||||||
|
{0, 65535, ast::BuiltInClass::UNSIGNED_16},
|
||||||
|
{-32768, 32767, ast::BuiltInClass::SIGNED_16},
|
||||||
|
{0, 4294967295, ast::BuiltInClass::UNSIGNED_32},
|
||||||
|
{-2147483648, 2147483647, ast::BuiltInClass::SIGNED_32},
|
||||||
|
};
|
||||||
|
|
||||||
|
for(const auto& range : integers) {
|
||||||
|
if((range.low == low_value || range.low == -low_value) && range.high == high_value) {
|
||||||
|
return range.classification;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CCC_FAILURE("Failed to classify range.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<std::unique_ptr<ast::Node>> field_to_ast(
|
||||||
|
const StabsStructOrUnionType::Field& field,
|
||||||
|
const StabsType& enclosing_struct,
|
||||||
|
const StabsToAstState& state,
|
||||||
|
s32 depth)
|
||||||
|
{
|
||||||
|
AST_DEBUG_PRINTF("%-*s field %s\n", depth * 4, "", field.name.c_str());
|
||||||
|
|
||||||
|
Result<bool> is_bitfield = detect_bitfield(field, state);
|
||||||
|
CCC_RETURN_IF_ERROR(is_bitfield);
|
||||||
|
|
||||||
|
if(*is_bitfield) {
|
||||||
|
// Process bitfields.
|
||||||
|
auto bitfield_node = stabs_type_to_ast(
|
||||||
|
*field.type,
|
||||||
|
&enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
false);
|
||||||
|
CCC_RETURN_IF_ERROR(bitfield_node);
|
||||||
|
|
||||||
|
std::unique_ptr<ast::BitField> bitfield = std::make_unique<ast::BitField>();
|
||||||
|
bitfield->name = (field.name == " ") ? "" : field.name;
|
||||||
|
bitfield->offset_bytes = field.offset_bits / 8;
|
||||||
|
bitfield->size_bits = field.size_bits;
|
||||||
|
bitfield->underlying_type = std::move(*bitfield_node);
|
||||||
|
bitfield->bitfield_offset_bits = field.offset_bits % 8;
|
||||||
|
bitfield->set_access_specifier(stabs_field_visibility_to_access_specifier(field.visibility), state.importer_flags);
|
||||||
|
|
||||||
|
return std::unique_ptr<ast::Node>(std::move(bitfield));
|
||||||
|
} else {
|
||||||
|
// Process a normal field.
|
||||||
|
Result<std::unique_ptr<ast::Node>> node = stabs_type_to_ast(
|
||||||
|
*field.type,
|
||||||
|
&enclosing_struct,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
false);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
|
||||||
|
(*node)->name = field.name;
|
||||||
|
(*node)->offset_bytes = field.offset_bits / 8;
|
||||||
|
(*node)->size_bits = field.size_bits;
|
||||||
|
(*node)->set_access_specifier(stabs_field_visibility_to_access_specifier(field.visibility), state.importer_flags);
|
||||||
|
|
||||||
|
if(field.name.starts_with("$vf") || field.name.starts_with("_vptr$") || field.name.starts_with("_vptr.")) {
|
||||||
|
(*node)->is_vtable_pointer = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(field.is_static) {
|
||||||
|
(*node)->storage_class = STORAGE_CLASS_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<bool> detect_bitfield(const StabsStructOrUnionType::Field& field, const StabsToAstState& state)
|
||||||
|
{
|
||||||
|
// Static fields can't be bitfields.
|
||||||
|
if(field.is_static) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve type references.
|
||||||
|
const StabsType* type = field.type.get();
|
||||||
|
for(s32 i = 0; i < 50; i++) {
|
||||||
|
if(!type->descriptor.has_value()) {
|
||||||
|
if(!type->type_number.valid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto next_type = state.stabs_types->find(type->type_number);
|
||||||
|
if(next_type == state.stabs_types->end() || next_type->second == type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
type = next_type->second;
|
||||||
|
} else if(type->descriptor == StabsTypeDescriptor::TYPE_REFERENCE) {
|
||||||
|
type = type->as<StabsTypeReferenceType>().type.get();
|
||||||
|
} else if(type->descriptor == StabsTypeDescriptor::CONST_QUALIFIER) {
|
||||||
|
type = type->as<StabsConstQualifierType>().type.get();
|
||||||
|
} else if(type->descriptor == StabsTypeDescriptor::VOLATILE_QUALIFIER) {
|
||||||
|
type = type->as<StabsVolatileQualifierType>().type.get();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent an infinite loop if there's a cycle (fatal frame).
|
||||||
|
if(i == 49) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the size of the underlying type.
|
||||||
|
s32 underlying_type_size_bits = 0;
|
||||||
|
switch(*type->descriptor) {
|
||||||
|
case ccc::StabsTypeDescriptor::RANGE: {
|
||||||
|
Result<ast::BuiltInClass> bclass = classify_range(type->as<StabsRangeType>());
|
||||||
|
CCC_RETURN_IF_ERROR(bclass);
|
||||||
|
underlying_type_size_bits = builtin_class_size(*bclass) * 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ccc::StabsTypeDescriptor::CROSS_REFERENCE: {
|
||||||
|
if(type->as<StabsCrossReferenceType>().type == ast::ForwardDeclaredType::ENUM) {
|
||||||
|
underlying_type_size_bits = 32;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ccc::StabsTypeDescriptor::TYPE_ATTRIBUTE: {
|
||||||
|
underlying_type_size_bits = (s32) type->as<StabsSizeTypeAttributeType>().size_bits;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ccc::StabsTypeDescriptor::BUILTIN: {
|
||||||
|
underlying_type_size_bits = 8; // bool
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(underlying_type_size_bits == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return field.size_bits != underlying_type_size_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<std::vector<std::unique_ptr<ast::Node>>> member_functions_to_ast(
|
||||||
|
const StabsStructOrUnionType& type, const StabsToAstState& state, s32 depth)
|
||||||
|
{
|
||||||
|
if(state.importer_flags & NO_MEMBER_FUNCTIONS) {
|
||||||
|
return std::vector<std::unique_ptr<ast::Node>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view type_name_no_template_args;
|
||||||
|
if(type.name.has_value()) {
|
||||||
|
type_name_no_template_args =
|
||||||
|
std::string_view(*type.name).substr(0, type.name->find("<"));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<ast::Node>> member_functions;
|
||||||
|
bool only_special_functions = true;
|
||||||
|
|
||||||
|
for(const StabsStructOrUnionType::MemberFunctionSet& function_set : type.member_functions) {
|
||||||
|
MemberFunctionInfo info = check_member_function(
|
||||||
|
function_set.name, type_name_no_template_args, state.demangler, state.importer_flags);
|
||||||
|
|
||||||
|
if(!info.is_special_member_function) {
|
||||||
|
only_special_functions = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const StabsStructOrUnionType::MemberFunction& stabs_func : function_set.overloads) {
|
||||||
|
auto node = stabs_type_to_ast(
|
||||||
|
*stabs_func.type,
|
||||||
|
&type,
|
||||||
|
state,
|
||||||
|
depth + 1,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
CCC_RETURN_IF_ERROR(node);
|
||||||
|
|
||||||
|
(*node)->is_constructor_or_destructor = info.is_constructor_or_destructor;
|
||||||
|
(*node)->is_special_member_function = info.is_special_member_function;
|
||||||
|
(*node)->is_operator_member_function = info.is_operator_member_function;
|
||||||
|
|
||||||
|
(*node)->name = info.name;
|
||||||
|
(*node)->set_access_specifier(stabs_field_visibility_to_access_specifier(stabs_func.visibility), state.importer_flags);
|
||||||
|
|
||||||
|
if((*node)->descriptor == ast::FUNCTION) {
|
||||||
|
ast::Function& function = (*node)->as<ast::Function>();
|
||||||
|
function.modifier = stabs_func.modifier;
|
||||||
|
function.vtable_index = stabs_func.vtable_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
member_functions.emplace_back(std::move(*node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(only_special_functions && (state.importer_flags & INCLUDE_GENERATED_MEMBER_FUNCTIONS) == 0) {
|
||||||
|
return std::vector<std::unique_ptr<ast::Node>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return member_functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemberFunctionInfo check_member_function(
|
||||||
|
const std::string& mangled_name,
|
||||||
|
std::string_view type_name_no_template_args,
|
||||||
|
const DemanglerFunctions& demangler,
|
||||||
|
u32 importer_flags)
|
||||||
|
{
|
||||||
|
MemberFunctionInfo info;
|
||||||
|
|
||||||
|
// Some compiler versions output gcc opnames for overloaded operators
|
||||||
|
// instead of their proper names.
|
||||||
|
if((importer_flags & DONT_DEMANGLE_NAMES) == 0 && demangler.cplus_demangle_opname) {
|
||||||
|
char* demangled_name = demangler.cplus_demangle_opname(mangled_name.c_str(), 0);
|
||||||
|
if(demangled_name) {
|
||||||
|
info.name = demangled_name;
|
||||||
|
free(reinterpret_cast<void*>(demangled_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(info.name.empty()) {
|
||||||
|
info.name = mangled_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_constructor =
|
||||||
|
info.name == "__ct" || // Takes a parameter to decide whether or not to construct virtual base classes.
|
||||||
|
info.name == "__comp_ctor" || // Constructs virtual base classes.
|
||||||
|
info.name == "__base_ctor"; // Does not construct virtual base classes.
|
||||||
|
|
||||||
|
if(!is_constructor && !type_name_no_template_args.empty()) {
|
||||||
|
is_constructor |= info.name == type_name_no_template_args; // Named constructor.
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_destructor =
|
||||||
|
info.name == "__dt" || // Takes parameters to decide whether or not to construct virtual base classes and/or delete the object.
|
||||||
|
info.name == "__comp_dtor" || // Destructs virtual base classes.
|
||||||
|
info.name == "__base_dtor" || // Does not construct virtual base classes.
|
||||||
|
info.name == "__deleting_dtor"; // Destructs virtual base clases then deletes the entire object.
|
||||||
|
|
||||||
|
if(!is_destructor && !info.name.empty()) {
|
||||||
|
is_destructor |= info.name[0] == '~' && std::string_view(info.name).substr(1) == type_name_no_template_args; // Named destructor.
|
||||||
|
}
|
||||||
|
|
||||||
|
info.is_constructor_or_destructor = is_constructor || is_destructor || info.name.starts_with("$_");
|
||||||
|
info.is_special_member_function = info.is_constructor_or_destructor || info.name == "operator=";
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fix_recursively_emitted_structures(
|
||||||
|
ast::StructOrUnion& outer_struct, const std::string& name, StabsTypeNumber type_number, SourceFileHandle file_handle)
|
||||||
|
{
|
||||||
|
// This is a rather peculiar case. For some compiler versions, when a struct
|
||||||
|
// or a union defined using a typedef is being emitted and it needs to
|
||||||
|
// reference itself from a member function parameter, it will emit its
|
||||||
|
// entire definition again in the middle of the first definition, although
|
||||||
|
// thankfully it won't recurse more than once.
|
||||||
|
//
|
||||||
|
// The game Sega Soccer Slam is affected by this. See the PeculiarParameter
|
||||||
|
// test case in mdebug_importer_tests.cpp for a bare bones example.
|
||||||
|
|
||||||
|
for(std::unique_ptr<ast::Node>& node : outer_struct.member_functions) {
|
||||||
|
if(node->descriptor != ast::FUNCTION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::Function& function = node->as<ast::Function>();
|
||||||
|
if(!function.parameters.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::unique_ptr<ast::Node>& parameter : *function.parameters) {
|
||||||
|
if(parameter->descriptor != ast::POINTER_OR_REFERENCE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::PointerOrReference& pointer_or_reference = parameter->as<ast::PointerOrReference>();
|
||||||
|
if(pointer_or_reference.value_type->descriptor != ast::STRUCT_OR_UNION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::StructOrUnion& inner_struct = pointer_or_reference.value_type->as<ast::StructOrUnion>();
|
||||||
|
|
||||||
|
// Since C++ doesn't allow struct definitions in function parameter
|
||||||
|
// lists normally, and most of the time the member function
|
||||||
|
// parameters aren't even filled in by GCC, this is a really rare
|
||||||
|
// case, so here we only bother to do some very basic checks to
|
||||||
|
// verify that the inner struct is similar to the outer struct.
|
||||||
|
if(inner_struct.base_classes.size() != outer_struct.base_classes.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(inner_struct.fields.size() != outer_struct.fields.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(inner_struct.member_functions.size() != outer_struct.member_functions.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type_name = std::make_unique<ast::TypeName>();
|
||||||
|
type_name->source = ast::TypeNameSource::REFERENCE;
|
||||||
|
type_name->unresolved_stabs = std::make_unique<ast::TypeName::UnresolvedStabs>();
|
||||||
|
type_name->unresolved_stabs->type_name = name;
|
||||||
|
type_name->unresolved_stabs->referenced_file_handle = file_handle;
|
||||||
|
type_name->unresolved_stabs->stabs_type_number = type_number;
|
||||||
|
pointer_or_reference.value_type = std::move(type_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::AccessSpecifier stabs_field_visibility_to_access_specifier(StabsStructOrUnionType::Visibility visibility)
|
||||||
|
{
|
||||||
|
ast::AccessSpecifier access_specifier = ast::AS_PUBLIC;
|
||||||
|
switch(visibility) {
|
||||||
|
case StabsStructOrUnionType::Visibility::NONE: access_specifier = ast::AS_PUBLIC; break;
|
||||||
|
case StabsStructOrUnionType::Visibility::PUBLIC: access_specifier = ast::AS_PUBLIC; break;
|
||||||
|
case StabsStructOrUnionType::Visibility::PROTECTED: access_specifier = ast::AS_PROTECTED; break;
|
||||||
|
case StabsStructOrUnionType::Visibility::PRIVATE: access_specifier = ast::AS_PRIVATE; break;
|
||||||
|
case StabsStructOrUnionType::Visibility::PUBLIC_OPTIMIZED_OUT: access_specifier = ast::AS_PUBLIC; break;
|
||||||
|
}
|
||||||
|
return access_specifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ast.h"
|
||||||
|
#include "stabs.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
struct StabsToAstState {
|
||||||
|
u32 file_handle;
|
||||||
|
std::map<StabsTypeNumber, const StabsType*>* stabs_types;
|
||||||
|
u32 importer_flags;
|
||||||
|
DemanglerFunctions demangler;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<std::unique_ptr<ast::Node>> stabs_type_to_ast(
|
||||||
|
const StabsType& type,
|
||||||
|
const StabsType* enclosing_struct,
|
||||||
|
const StabsToAstState& state,
|
||||||
|
s32 depth,
|
||||||
|
bool substitute_type_name,
|
||||||
|
bool force_substitute);
|
||||||
|
void fix_recursively_emitted_structures(
|
||||||
|
ast::StructOrUnion& outer_struct, const std::string& name, StabsTypeNumber type_number, SourceFileHandle file_handle);
|
||||||
|
ast::AccessSpecifier stabs_field_visibility_to_access_specifier(StabsStructOrUnionType::Visibility visibility);
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,721 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <atomic>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
// An X macro for all the symbol types.
|
||||||
|
#define CCC_FOR_EACH_SYMBOL_TYPE_DO_X \
|
||||||
|
CCC_X(DataType, data_types) \
|
||||||
|
CCC_X(Function, functions) \
|
||||||
|
CCC_X(GlobalVariable, global_variables) \
|
||||||
|
CCC_X(Label, labels) \
|
||||||
|
CCC_X(LocalVariable, local_variables) \
|
||||||
|
CCC_X(Module, modules) \
|
||||||
|
CCC_X(ParameterVariable, parameter_variables) \
|
||||||
|
CCC_X(Section, sections) \
|
||||||
|
CCC_X(SourceFile, source_files) \
|
||||||
|
CCC_X(SymbolSource, symbol_sources)
|
||||||
|
|
||||||
|
// An enum for all the symbol types.
|
||||||
|
enum SymbolDescriptor {
|
||||||
|
DATA_TYPE = 1 << 0,
|
||||||
|
FUNCTION = 1 << 1,
|
||||||
|
GLOBAL_VARIABLE = 1 << 2,
|
||||||
|
LABEL = 1 << 3,
|
||||||
|
LOCAL_VARIABLE = 1 << 4,
|
||||||
|
MODULE = 1 << 5,
|
||||||
|
PARAMETER_VARIABLE = 1 << 6,
|
||||||
|
SECTION = 1 << 7,
|
||||||
|
SOURCE_FILE = 1 << 8,
|
||||||
|
SYMBOL_SOURCE = 1 << 9
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ALL_SYMBOL_TYPES = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forward declare all the different types of symbol objects.
|
||||||
|
#define CCC_X(SymbolType, symbol_list) class SymbolType;
|
||||||
|
CCC_FOR_EACH_SYMBOL_TYPE_DO_X
|
||||||
|
#undef CCC_X
|
||||||
|
|
||||||
|
class SymbolDatabase;
|
||||||
|
|
||||||
|
// Strongly typed handles for all of the symbol objects. These are here to solve
|
||||||
|
// the problem of dangling references to symbols.
|
||||||
|
template <typename SymbolType>
|
||||||
|
struct SymbolHandle {
|
||||||
|
u32 value = (u32) -1;
|
||||||
|
|
||||||
|
SymbolHandle() {}
|
||||||
|
SymbolHandle(u32 v) : value(v) {}
|
||||||
|
SymbolHandle(const SymbolType* symbol)
|
||||||
|
: value(symbol ? symbol->handle().value : (u32) -1) {}
|
||||||
|
|
||||||
|
// Check if this symbol handle has been initialised. Note that this doesn't
|
||||||
|
// determine whether or not the symbol it points to has been deleted!
|
||||||
|
bool valid() const { return value != (u32) -1; }
|
||||||
|
|
||||||
|
friend auto operator<=>(const SymbolHandle& lhs, const SymbolHandle& rhs) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CCC_X(SymbolType, symbol_list) using SymbolType##Handle = SymbolHandle<SymbolType>;
|
||||||
|
CCC_FOR_EACH_SYMBOL_TYPE_DO_X
|
||||||
|
#undef CCC_X
|
||||||
|
|
||||||
|
enum SymbolFlag {
|
||||||
|
NO_SYMBOL_FLAGS = 0,
|
||||||
|
WITH_ADDRESS_MAP = 1 << 0,
|
||||||
|
WITH_NAME_MAP = 1 << 1,
|
||||||
|
NAME_NEEDS_DEMANGLING = 1 << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// A container class for symbols of a given type that maintains maps of their
|
||||||
|
// names and addresses depending on the value of SymbolType::FLAGS.
|
||||||
|
template <typename SymbolType>
|
||||||
|
class SymbolList {
|
||||||
|
public:
|
||||||
|
// Lookup symbols from their handles using binary search.
|
||||||
|
SymbolType* symbol_from_handle(SymbolHandle<SymbolType> handle);
|
||||||
|
const SymbolType* symbol_from_handle(SymbolHandle<SymbolType> handle) const;
|
||||||
|
|
||||||
|
// Lookup multiple symbols from their handles using binary search.
|
||||||
|
std::vector<SymbolType*> symbols_from_handles(const std::vector<SymbolHandle<SymbolType>>& handles);
|
||||||
|
std::vector<const SymbolType*> symbols_from_handles(const std::vector<SymbolHandle<SymbolType>>& handles) const;
|
||||||
|
std::vector<SymbolType*> optional_symbols_from_handles(const std::optional<std::vector<SymbolHandle<SymbolType>>>& handles);
|
||||||
|
std::vector<const SymbolType*> optional_symbols_from_handles(const std::optional<std::vector<SymbolHandle<SymbolType>>>& handles) const;
|
||||||
|
|
||||||
|
using Iterator = typename std::vector<SymbolType>::iterator;
|
||||||
|
using ConstIterator = typename std::vector<SymbolType>::const_iterator;
|
||||||
|
|
||||||
|
// For iterating over all the symbols.
|
||||||
|
Iterator begin();
|
||||||
|
ConstIterator begin() const;
|
||||||
|
Iterator end();
|
||||||
|
ConstIterator end() const;
|
||||||
|
|
||||||
|
using AddressToHandleMap = std::multimap<u32, SymbolHandle<SymbolType>>;
|
||||||
|
using NameToHandleMap = std::multimap<std::string, SymbolHandle<SymbolType>>;
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
class Iterators {
|
||||||
|
public:
|
||||||
|
Iterators(Iterator b, Iterator e)
|
||||||
|
: m_begin(b), m_end(e) {}
|
||||||
|
Iterator begin() const { return m_begin; }
|
||||||
|
Iterator end() const { return m_end; }
|
||||||
|
protected:
|
||||||
|
Iterator m_begin;
|
||||||
|
Iterator m_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
using AddressToHandleMapIterators = Iterators<typename AddressToHandleMap::const_iterator>;
|
||||||
|
using NameToHandleMapIterators = Iterators<typename NameToHandleMap::const_iterator>;
|
||||||
|
|
||||||
|
// Lookup symbols by their address.
|
||||||
|
AddressToHandleMapIterators handles_from_starting_address(Address address) const;
|
||||||
|
AddressToHandleMapIterators handles_from_address_range(AddressRange range) const;
|
||||||
|
SymbolHandle<SymbolType> first_handle_from_starting_address(Address address) const;
|
||||||
|
SymbolHandle<SymbolType> first_handle_after_address(Address address) const;
|
||||||
|
|
||||||
|
// Lookup symbols by their name.
|
||||||
|
NameToHandleMapIterators handles_from_name(const std::string& name) const;
|
||||||
|
SymbolHandle<SymbolType> first_handle_from_name(const std::string& name) const;
|
||||||
|
|
||||||
|
// Find a symbol with an address range that contains the provided address.
|
||||||
|
// For example, to find which function an instruction belongs to.
|
||||||
|
SymbolType* symbol_overlapping_address(Address address);
|
||||||
|
const SymbolType* symbol_overlapping_address(Address address) const;
|
||||||
|
|
||||||
|
// Convert handles to underlying array indices.
|
||||||
|
s32 index_from_handle(SymbolHandle<SymbolType> handle) const;
|
||||||
|
|
||||||
|
// Index into the underlying array.
|
||||||
|
SymbolType& symbol_from_index(s32 index);
|
||||||
|
const SymbolType& symbol_from_index(s32 index) const;
|
||||||
|
|
||||||
|
// Determine if any symbols are being stored.
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
// Retrieve the number of symbols stored.
|
||||||
|
s32 size() const;
|
||||||
|
|
||||||
|
// Create a new symbol. If it's a SymbolSource symbol, source can be left
|
||||||
|
// empty, otherwise it has to be valid.
|
||||||
|
Result<SymbolType*> create_symbol(
|
||||||
|
std::string name, Address address, SymbolSourceHandle source, const Module* module_symbol = nullptr);
|
||||||
|
|
||||||
|
// Create a new symbol. Similar to above, but for symbols without addresses.
|
||||||
|
Result<SymbolType*> create_symbol(
|
||||||
|
std::string name, SymbolSourceHandle source, const Module* module_symbol = nullptr);
|
||||||
|
|
||||||
|
// Create a new symbol. Similar to above, but unless DONT_DEMANGLE_NAMES is
|
||||||
|
// set, the name of the symbol will be demangled.
|
||||||
|
Result<SymbolType*> create_symbol(
|
||||||
|
std::string name,
|
||||||
|
SymbolSourceHandle source,
|
||||||
|
const Module* module_symbol,
|
||||||
|
Address address,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler);
|
||||||
|
|
||||||
|
// Update the address of a symbol without changing its handle.
|
||||||
|
bool move_symbol(SymbolHandle<SymbolType> handle, Address new_address);
|
||||||
|
|
||||||
|
// Update the name of a symbol without changing its handle.
|
||||||
|
bool rename_symbol(SymbolHandle<SymbolType> handle, std::string new_name);
|
||||||
|
|
||||||
|
// Move all the symbols from the passed list into this list.
|
||||||
|
void merge_from(SymbolList<SymbolType>& list);
|
||||||
|
|
||||||
|
// Mark a symbol for destruction. If the correct symbol database pointer is
|
||||||
|
// passed, all descendants will also be marked. For example, marking a
|
||||||
|
// function will also mark its parameters and local variables.
|
||||||
|
bool mark_symbol_for_destruction(SymbolHandle<SymbolType> handle, SymbolDatabase* database);
|
||||||
|
|
||||||
|
// Mark all the symbols from a given symbol source for destruction. For
|
||||||
|
// example you can use this to free a symbol table without destroying
|
||||||
|
// user-defined symbols. The behaviour for marking descendants is the same
|
||||||
|
// as destroy_symbol.
|
||||||
|
void mark_symbols_from_source_for_destruction(SymbolSourceHandle source, SymbolDatabase* database);
|
||||||
|
|
||||||
|
// Mark all the symbols from a given module for destruction. The behaviour
|
||||||
|
// for marking descendants is the same as destroy_symbol.
|
||||||
|
void mark_symbols_from_module_for_destruction(ModuleHandle module_handle, SymbolDatabase* database);
|
||||||
|
|
||||||
|
// Destroy all symbols that have previously been marked for destruction.
|
||||||
|
// This invalidates all pointers to symbols in this list.
|
||||||
|
void destroy_marked_symbols();
|
||||||
|
|
||||||
|
// Destroy all symbols, but don't reset m_next_handle so we don't have to
|
||||||
|
// worry about dangling handles.
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Do a binary search for a handle, and return either its index, or the
|
||||||
|
// index where it could be inserted.
|
||||||
|
size_t binary_search(SymbolHandle<SymbolType> handle) const;
|
||||||
|
|
||||||
|
// Keep the address map in sync with the symbol list.
|
||||||
|
void link_address_map(SymbolType& symbol);
|
||||||
|
void unlink_address_map(SymbolType& symbol);
|
||||||
|
|
||||||
|
// Keep the name map in sync with the symbol list.
|
||||||
|
void link_name_map(SymbolType& symbol);
|
||||||
|
void unlink_name_map(SymbolType& symbol);
|
||||||
|
|
||||||
|
std::vector<SymbolType> m_symbols;
|
||||||
|
AddressToHandleMap m_address_to_handle;
|
||||||
|
NameToHandleMap m_name_to_handle;
|
||||||
|
|
||||||
|
// We share this between symbol lists of the same type so that we can merge
|
||||||
|
// them without having to rewrite all the handles.
|
||||||
|
static std::atomic<u32> m_next_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class for all the symbols.
|
||||||
|
class Symbol {
|
||||||
|
template <typename SymbolType>
|
||||||
|
friend class SymbolList;
|
||||||
|
public:
|
||||||
|
const std::string& name() const { return m_name; }
|
||||||
|
u32 raw_handle() const { return m_handle; }
|
||||||
|
SymbolSourceHandle source() const { return m_source; }
|
||||||
|
ModuleHandle module_handle() const { return m_module; }
|
||||||
|
|
||||||
|
Address address() const { return m_address; }
|
||||||
|
u32 size() const { return m_size; }
|
||||||
|
void set_size(u32 size) { m_size = size; }
|
||||||
|
AddressRange address_range() const { return AddressRange(m_address, m_address.get_or_zero() + m_size); }
|
||||||
|
|
||||||
|
ast::Node* type() { return m_type.get(); }
|
||||||
|
const ast::Node* type() const { return m_type.get(); }
|
||||||
|
void set_type(std::unique_ptr<ast::Node> type);
|
||||||
|
|
||||||
|
u32 generation() const { return m_generation; }
|
||||||
|
|
||||||
|
// This MUST be called after any AST nodes have been created/deleted/moved.
|
||||||
|
// For the set_type function this is done for you.
|
||||||
|
void invalidate_node_handles() { m_generation++; }
|
||||||
|
|
||||||
|
// Mark a single symbol for destruction, not including its descendants.
|
||||||
|
void mark_for_destruction() { m_marked_for_destruction = true; }
|
||||||
|
bool is_marked_for_destruction() { return m_marked_for_destruction; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void on_create() {}
|
||||||
|
void on_destroy(SymbolDatabase* database) {}
|
||||||
|
|
||||||
|
u32 m_handle = (u32) -1;
|
||||||
|
SymbolSourceHandle m_source;
|
||||||
|
Address m_address;
|
||||||
|
u32 m_size = 0;
|
||||||
|
std::string m_name;
|
||||||
|
std::unique_ptr<ast::Node> m_type;
|
||||||
|
u32 m_generation : 31 = 0;
|
||||||
|
u32 m_marked_for_destruction : 1 = false;
|
||||||
|
ModuleHandle m_module;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Variable storage types. This is different to whether the variable is a
|
||||||
|
// global, local or parameter. For example local variables can have global
|
||||||
|
// storage (static locals).
|
||||||
|
|
||||||
|
enum GlobalStorageLocation {
|
||||||
|
NIL,
|
||||||
|
DATA,
|
||||||
|
BSS,
|
||||||
|
ABS,
|
||||||
|
SDATA,
|
||||||
|
SBSS,
|
||||||
|
RDATA,
|
||||||
|
COMMON,
|
||||||
|
SCOMMON,
|
||||||
|
SUNDEFINED
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* global_storage_location_to_string(GlobalStorageLocation location);
|
||||||
|
|
||||||
|
struct GlobalStorage {
|
||||||
|
GlobalStorageLocation location = GlobalStorageLocation::NIL;
|
||||||
|
|
||||||
|
GlobalStorage() {}
|
||||||
|
friend auto operator<=>(const GlobalStorage& lhs, const GlobalStorage& rhs) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RegisterStorage {
|
||||||
|
s32 dbx_register_number = -1;
|
||||||
|
bool is_by_reference;
|
||||||
|
|
||||||
|
RegisterStorage() {}
|
||||||
|
friend auto operator<=>(const RegisterStorage& lhs, const RegisterStorage& rhs) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StackStorage {
|
||||||
|
s32 stack_pointer_offset = -1;
|
||||||
|
|
||||||
|
StackStorage() {}
|
||||||
|
friend auto operator<=>(const StackStorage& lhs, const StackStorage& rhs) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The hashing algorithm for functions. If you change this algorithm make sure
|
||||||
|
// to bump the version number for the JSON format so we can know if a hash was
|
||||||
|
// generated using the new algorithm or not.
|
||||||
|
class FunctionHash {
|
||||||
|
public:
|
||||||
|
void update(u32 instruction)
|
||||||
|
{
|
||||||
|
// Separate out the opcode so that the hash remains the same regardless
|
||||||
|
// of if relocations are applied or not.
|
||||||
|
u32 opcode = instruction >> 26;
|
||||||
|
m_hash = m_hash * 31 + opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 get() const
|
||||||
|
{
|
||||||
|
return m_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
u32 m_hash = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// All the different types of symbol objects.
|
||||||
|
|
||||||
|
// A C/C++ data type.
|
||||||
|
class DataType : public Symbol {
|
||||||
|
friend SourceFile;
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = DATA_TYPE;
|
||||||
|
static constexpr const char* NAME = "Data Type";
|
||||||
|
static constexpr const u32 FLAGS = WITH_NAME_MAP;
|
||||||
|
|
||||||
|
DataTypeHandle handle() const { return m_handle; }
|
||||||
|
|
||||||
|
std::vector<SourceFileHandle> files; // List of files for which a given top-level type is present.
|
||||||
|
const char* compare_fail_reason = nullptr;
|
||||||
|
|
||||||
|
bool not_defined_in_any_translation_unit : 1 = false;
|
||||||
|
bool only_defined_in_single_translation_unit : 1 = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A function. The type stored is the return type.
|
||||||
|
class Function : public Symbol {
|
||||||
|
friend SourceFile;
|
||||||
|
friend SymbolList<Function>;
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = FUNCTION;
|
||||||
|
static constexpr const char* NAME = "Function";
|
||||||
|
static constexpr const u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP | NAME_NEEDS_DEMANGLING;
|
||||||
|
|
||||||
|
FunctionHandle handle() const { return m_handle; }
|
||||||
|
SourceFileHandle source_file() const { return m_source_file; }
|
||||||
|
|
||||||
|
const std::optional<std::vector<ParameterVariableHandle>>& parameter_variables() const;
|
||||||
|
void set_parameter_variables(std::optional<std::vector<ParameterVariableHandle>> parameter_variables, SymbolDatabase& database);
|
||||||
|
|
||||||
|
const std::optional<std::vector<LocalVariableHandle>>& local_variables() const;
|
||||||
|
void set_local_variables(std::optional<std::vector<LocalVariableHandle>> local_variables, SymbolDatabase& database);
|
||||||
|
|
||||||
|
const std::string& mangled_name() const;
|
||||||
|
void set_mangled_name(std::string mangled);
|
||||||
|
|
||||||
|
// A hash of all the opcodes in the function, read from file.
|
||||||
|
u32 original_hash() const;
|
||||||
|
void set_original_hash(u32 hash);
|
||||||
|
|
||||||
|
// A hash of all the opcodes in the function, read from memory.
|
||||||
|
u32 current_hash() const;
|
||||||
|
void set_current_hash(FunctionHash hash);
|
||||||
|
|
||||||
|
struct LineNumberPair {
|
||||||
|
Address address;
|
||||||
|
s32 line_number;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SubSourceFile {
|
||||||
|
Address address;
|
||||||
|
std::string relative_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string relative_path;
|
||||||
|
StorageClass storage_class;
|
||||||
|
s32 stack_frame_size = -1;
|
||||||
|
std::vector<LineNumberPair> line_numbers;
|
||||||
|
std::vector<SubSourceFile> sub_source_files;
|
||||||
|
bool is_member_function_ish = false; // Filled in by fill_in_pointers_to_member_function_definitions.
|
||||||
|
bool is_no_return = false;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void on_destroy(SymbolDatabase* database);
|
||||||
|
|
||||||
|
SourceFileHandle m_source_file;
|
||||||
|
std::optional<std::vector<ParameterVariableHandle>> m_parameter_variables;
|
||||||
|
std::optional<std::vector<LocalVariableHandle>> m_local_variables;
|
||||||
|
|
||||||
|
std::string m_mangled_name;
|
||||||
|
|
||||||
|
u32 m_original_hash = 0;
|
||||||
|
u32 m_current_hash = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A global variable.
|
||||||
|
class GlobalVariable : public Symbol {
|
||||||
|
friend SourceFile;
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = GLOBAL_VARIABLE;
|
||||||
|
static constexpr const char* NAME = "Global Variable";
|
||||||
|
static constexpr u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP | NAME_NEEDS_DEMANGLING;
|
||||||
|
|
||||||
|
GlobalVariableHandle handle() const { return m_handle; }
|
||||||
|
SourceFileHandle source_file() const { return m_source_file; };
|
||||||
|
|
||||||
|
const std::string& mangled_name() const;
|
||||||
|
void set_mangled_name(std::string mangled);
|
||||||
|
|
||||||
|
GlobalStorage storage;
|
||||||
|
StorageClass storage_class;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SourceFileHandle m_source_file;
|
||||||
|
std::string m_mangled_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A label. This could be a label defined in assembly, C/C++, or just a symbol
|
||||||
|
// that we can't automatically determine the type of (e.g. SNDLL symbols).
|
||||||
|
class Label : public Symbol {
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = LABEL;
|
||||||
|
static constexpr const char* NAME = "Label";
|
||||||
|
static constexpr u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP;
|
||||||
|
|
||||||
|
LabelHandle handle() const { return m_handle; }
|
||||||
|
|
||||||
|
// Indicates that this label should not be used as a function name.
|
||||||
|
bool is_junk = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A local variable. This includes static local variables which have global
|
||||||
|
// storage.
|
||||||
|
class LocalVariable : public Symbol {
|
||||||
|
friend Function;
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = LOCAL_VARIABLE;
|
||||||
|
static constexpr const char* NAME = "Local Variable";
|
||||||
|
static constexpr u32 FLAGS = WITH_ADDRESS_MAP;
|
||||||
|
|
||||||
|
LocalVariableHandle handle() const { return m_handle; }
|
||||||
|
FunctionHandle function() const { return m_function; };
|
||||||
|
|
||||||
|
std::variant<GlobalStorage, RegisterStorage, StackStorage> storage;
|
||||||
|
AddressRange live_range;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FunctionHandle m_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A program module e.g. an ELF file or an SNDLL file. Every symbol has a module
|
||||||
|
// field indicating what module the symbol belongs to. This can be used to
|
||||||
|
// delete all the symbols associated with a given module. Additionally, when a
|
||||||
|
// valid module pointer is passed to SymbolList<>::create_symbol, the address of
|
||||||
|
// the symbol will be added to the address of the new symbol.
|
||||||
|
class Module : public Symbol {
|
||||||
|
friend SymbolList<Module>;
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = MODULE;
|
||||||
|
static constexpr const char* NAME = "Module";
|
||||||
|
static constexpr u32 FLAGS = WITH_NAME_MAP;
|
||||||
|
|
||||||
|
ModuleHandle handle() const { return m_handle; }
|
||||||
|
|
||||||
|
// These are used for IRX modules.
|
||||||
|
bool is_irx = false;
|
||||||
|
s32 version_major = -1;
|
||||||
|
s32 version_minor = -1;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void on_create();
|
||||||
|
};
|
||||||
|
|
||||||
|
// A parameter variable.
|
||||||
|
class ParameterVariable : public Symbol {
|
||||||
|
friend Function;
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = PARAMETER_VARIABLE;
|
||||||
|
static constexpr const char* NAME = "Parameter Variable";
|
||||||
|
static constexpr u32 FLAGS = NO_SYMBOL_FLAGS;
|
||||||
|
|
||||||
|
ParameterVariableHandle handle() const { return m_handle; }
|
||||||
|
FunctionHandle function() const { return m_function; };
|
||||||
|
|
||||||
|
std::variant<RegisterStorage, StackStorage> storage;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FunctionHandle m_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
// An ELF section. These are created from the ELF section headers.
|
||||||
|
class Section : public Symbol {
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = SECTION;
|
||||||
|
static constexpr const char* NAME = "Section";
|
||||||
|
static constexpr u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP;
|
||||||
|
|
||||||
|
SectionHandle handle() const { return m_handle; }
|
||||||
|
|
||||||
|
// Check if the section name is ".text".
|
||||||
|
bool contains_code() const;
|
||||||
|
|
||||||
|
// Check for known data section names.
|
||||||
|
bool contains_data() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A source file (.c or .cpp file). One of these will be created for every
|
||||||
|
// translation unit in the program (but only if debugging symbols are present).
|
||||||
|
class SourceFile : public Symbol {
|
||||||
|
friend SymbolList<SourceFile>;
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = SOURCE_FILE;
|
||||||
|
static constexpr const char* NAME = "Source File";
|
||||||
|
static constexpr u32 FLAGS = WITH_ADDRESS_MAP | WITH_NAME_MAP;
|
||||||
|
|
||||||
|
SourceFileHandle handle() const { return m_handle; }
|
||||||
|
const std::string& full_path() const { return name(); }
|
||||||
|
|
||||||
|
const std::vector<FunctionHandle>& functions() const;
|
||||||
|
void set_functions(std::vector<FunctionHandle> functions, SymbolDatabase& database);
|
||||||
|
|
||||||
|
const std::vector<GlobalVariableHandle>& global_variables() const;
|
||||||
|
void set_global_variables(std::vector<GlobalVariableHandle> global_variables, SymbolDatabase& database);
|
||||||
|
|
||||||
|
// Check whether at least half of the functions associated with the source
|
||||||
|
// file match their original hash (meaning they haven't been overwritten).
|
||||||
|
bool functions_match() const;
|
||||||
|
void check_functions_match(const SymbolDatabase& database);
|
||||||
|
|
||||||
|
std::string working_dir;
|
||||||
|
std::string command_line_path;
|
||||||
|
std::map<StabsTypeNumber, DataTypeHandle> stabs_type_number_to_handle;
|
||||||
|
std::set<std::string> toolchain_version_info;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void on_destroy(SymbolDatabase* database);
|
||||||
|
|
||||||
|
std::vector<FunctionHandle> m_functions;
|
||||||
|
std::vector<GlobalVariableHandle> m_global_variables;
|
||||||
|
bool m_functions_match = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A symbol source. Every symbol has a symbol source field indicating how the
|
||||||
|
// symbol was created. For example, the symbol table importers will each create
|
||||||
|
// one of these (if it doesn't already exist).
|
||||||
|
class SymbolSource : public Symbol {
|
||||||
|
friend SymbolList<SymbolSource>;
|
||||||
|
public:
|
||||||
|
static constexpr const SymbolDescriptor DESCRIPTOR = SYMBOL_SOURCE;
|
||||||
|
static constexpr const char* NAME = "Symbol Source";
|
||||||
|
static constexpr u32 FLAGS = WITH_NAME_MAP;
|
||||||
|
|
||||||
|
SymbolSourceHandle handle() const { return m_handle; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void on_create();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bundles together all the information needed to identify if a symbol came from
|
||||||
|
// a specific symbol table import operation. For example, this is used to make
|
||||||
|
// sure that we don't reference symbols from another symbol table during the
|
||||||
|
// import process.
|
||||||
|
struct SymbolGroup {
|
||||||
|
SymbolSourceHandle source;
|
||||||
|
Module* module_symbol = nullptr;
|
||||||
|
|
||||||
|
bool is_in_group(const Symbol& symbol) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The symbol database itself. This owns all the symbols.
|
||||||
|
class SymbolDatabase {
|
||||||
|
public:
|
||||||
|
SymbolList<DataType> data_types;
|
||||||
|
SymbolList<Function> functions;
|
||||||
|
SymbolList<GlobalVariable> global_variables;
|
||||||
|
SymbolList<Label> labels;
|
||||||
|
SymbolList<LocalVariable> local_variables;
|
||||||
|
SymbolList<Module> modules;
|
||||||
|
SymbolList<ParameterVariable> parameter_variables;
|
||||||
|
SymbolList<Section> sections;
|
||||||
|
SymbolList<SourceFile> source_files;
|
||||||
|
SymbolList<SymbolSource> symbol_sources;
|
||||||
|
|
||||||
|
// Sum up the symbol counts for each symbol list.
|
||||||
|
s32 symbol_count() const;
|
||||||
|
|
||||||
|
// Find a symbol of any of the specified types given an address. Symbols of
|
||||||
|
// the types specified higher up in the CCC_FOR_EACH_SYMBOL_TYPE_DO_X macro
|
||||||
|
// are checked for first.
|
||||||
|
const Symbol* symbol_starting_at_address(
|
||||||
|
Address address, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const;
|
||||||
|
const Symbol* symbol_after_address(
|
||||||
|
Address address, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const;
|
||||||
|
const Symbol* symbol_overlapping_address(
|
||||||
|
Address address, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const;
|
||||||
|
|
||||||
|
// Find a symbol of any of the specified types given its name. Symbols of
|
||||||
|
// the types specified higher up in the CCC_FOR_EACH_SYMBOL_TYPE_DO_X macro
|
||||||
|
// are checked for first.
|
||||||
|
const Symbol* symbol_with_name(
|
||||||
|
const std::string& name, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const;
|
||||||
|
|
||||||
|
// Finds a symbol source object with the given name or creates one if it
|
||||||
|
// doesn't already exist.
|
||||||
|
Result<SymbolSourceHandle> get_symbol_source(const std::string& name);
|
||||||
|
|
||||||
|
// Deduplicate matching data types with the same name. May replace the
|
||||||
|
// existing data type with the new one if the new one is better.
|
||||||
|
Result<DataType*> create_data_type_if_unique(
|
||||||
|
std::unique_ptr<ast::Node> node,
|
||||||
|
StabsTypeNumber number,
|
||||||
|
const char* name,
|
||||||
|
SourceFile& source_file,
|
||||||
|
const SymbolGroup& group);
|
||||||
|
|
||||||
|
// Move all the symbols in the passed database into this database.
|
||||||
|
void merge_from(SymbolDatabase& database);
|
||||||
|
|
||||||
|
// Destroy all the symbols from a given symbol source. For example you can
|
||||||
|
// use this to free a symbol table without destroying user-defined symbols.
|
||||||
|
void destroy_symbols_from_source(SymbolSourceHandle source, bool destroy_descendants);
|
||||||
|
|
||||||
|
// Destroy all the symbols from a given module.
|
||||||
|
void destroy_symbols_from_module(ModuleHandle module_handle, bool destroy_descendants);
|
||||||
|
|
||||||
|
// Destroy all the symbols that have previously been marked for destruction.
|
||||||
|
// This invalidates all pointers to symbols in this database.
|
||||||
|
void destroy_marked_symbols();
|
||||||
|
|
||||||
|
// Destroy all the symbols in the symbol database.
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
template <typename Callback>
|
||||||
|
void for_each_symbol(Callback callback) {
|
||||||
|
// Use indices here to avoid iterator invalidation.
|
||||||
|
#define CCC_X(SymbolType, symbol_list) \
|
||||||
|
for(s32 i = 0; i < symbol_list.size(); i++) { \
|
||||||
|
callback(symbol_list.symbol_from_index(i)); \
|
||||||
|
}
|
||||||
|
CCC_FOR_EACH_SYMBOL_TYPE_DO_X
|
||||||
|
#undef CCC_X
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A handle to a symbol of any type.
|
||||||
|
class MultiSymbolHandle {
|
||||||
|
public:
|
||||||
|
// Create an empty multi symbol handle.
|
||||||
|
MultiSymbolHandle();
|
||||||
|
|
||||||
|
// Create a multi symbol handle of the specified type.
|
||||||
|
template <typename SymbolType>
|
||||||
|
MultiSymbolHandle(const SymbolType& symbol);
|
||||||
|
MultiSymbolHandle(SymbolDescriptor descriptor, u32 handle);
|
||||||
|
|
||||||
|
bool valid() const;
|
||||||
|
SymbolDescriptor descriptor() const;
|
||||||
|
u32 handle() const;
|
||||||
|
|
||||||
|
Symbol* lookup_symbol(SymbolDatabase& database);
|
||||||
|
const Symbol* lookup_symbol(const SymbolDatabase& database) const;
|
||||||
|
|
||||||
|
bool is_flag_set(SymbolFlag flag) const;
|
||||||
|
bool move_symbol(Address new_address, SymbolDatabase& database) const;
|
||||||
|
bool rename_symbol(std::string new_name, SymbolDatabase& database) const;
|
||||||
|
bool destroy_symbol(SymbolDatabase& database, bool destroy_descendants) const;
|
||||||
|
|
||||||
|
friend auto operator<=>(const MultiSymbolHandle& lhs, const MultiSymbolHandle& rhs) = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SymbolDescriptor m_descriptor = DATA_TYPE;
|
||||||
|
u32 m_handle = (u32) -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A handle to an AST node.
|
||||||
|
class NodeHandle {
|
||||||
|
friend SymbolDatabase;
|
||||||
|
public:
|
||||||
|
// Create an empty node handle.
|
||||||
|
NodeHandle();
|
||||||
|
|
||||||
|
// Create a node handle that will always allow accesses to its node. You
|
||||||
|
// should only use this if you know the lifetime of the handle is a subset
|
||||||
|
// of the lifetime of the node.
|
||||||
|
NodeHandle(const ast::Node* node);
|
||||||
|
|
||||||
|
// Create a node handle pointing to an AST node from a given symbol that
|
||||||
|
// will prevent accesses to the node if the symbol is deleted.
|
||||||
|
template <typename SymbolType>
|
||||||
|
NodeHandle(const SymbolType& symbol, const ast::Node* node);
|
||||||
|
NodeHandle(SymbolDescriptor descriptor, const Symbol& symbol, const ast::Node* node);
|
||||||
|
|
||||||
|
bool valid() const;
|
||||||
|
const MultiSymbolHandle& symbol() const;
|
||||||
|
|
||||||
|
const ast::Node* lookup_node(const SymbolDatabase& database) const;
|
||||||
|
NodeHandle handle_for_child(const ast::Node* child_node) const;
|
||||||
|
|
||||||
|
friend auto operator<=>(const NodeHandle& lhs, const NodeHandle& rhs) = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MultiSymbolHandle m_symbol;
|
||||||
|
const ast::Node* m_node = nullptr;
|
||||||
|
u32 m_generation = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "symbol_file.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
Result<std::unique_ptr<SymbolFile>> parse_symbol_file(std::vector<u8> image, std::string file_name)
|
||||||
|
{
|
||||||
|
const std::optional<u32> magic = copy_unaligned<u32>(image, 0);
|
||||||
|
CCC_CHECK(magic.has_value(), "File too small.");
|
||||||
|
|
||||||
|
std::unique_ptr<SymbolFile> symbol_file;
|
||||||
|
|
||||||
|
switch(*magic) {
|
||||||
|
case CCC_FOURCC("\x7f""ELF"): {
|
||||||
|
Result<ElfFile> elf = ElfFile::parse(std::move(image));
|
||||||
|
CCC_RETURN_IF_ERROR(elf);
|
||||||
|
|
||||||
|
symbol_file = std::make_unique<ElfSymbolFile>(std::move(*elf), std::move(file_name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CCC_FOURCC("SNR1"):
|
||||||
|
case CCC_FOURCC("SNR2"): {
|
||||||
|
Result<SNDLLFile> sndll = parse_sndll_file(image, Address(), SNDLLType::DYNAMIC_LIBRARY);
|
||||||
|
CCC_RETURN_IF_ERROR(sndll);
|
||||||
|
|
||||||
|
symbol_file = std::make_unique<SNDLLSymbolFile>(std::make_shared<SNDLLFile>(std::move(*sndll)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return CCC_FAILURE("Unknown file type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfSymbolFile::ElfSymbolFile(ElfFile elf, std::string elf_name)
|
||||||
|
: m_elf(std::move(elf)), m_name(std::move(elf_name)) {}
|
||||||
|
|
||||||
|
std::string ElfSymbolFile::name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::vector<std::unique_ptr<SymbolTable>>> ElfSymbolFile::get_all_symbol_tables() const
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<SymbolTable>> symbol_tables;
|
||||||
|
|
||||||
|
symbol_tables.emplace_back(std::make_unique<ElfSectionHeadersSymbolTable>(m_elf));
|
||||||
|
|
||||||
|
for(size_t i = 0; i < SYMBOL_TABLE_FORMATS.size(); i++) {
|
||||||
|
const SymbolTableFormatInfo& info = SYMBOL_TABLE_FORMATS[i];
|
||||||
|
|
||||||
|
const ElfSection* section = m_elf.lookup_section(info.section_name);
|
||||||
|
if(section) {
|
||||||
|
Result<std::unique_ptr<SymbolTable>> symbol_table = create_elf_symbol_table(*section, m_elf, info.format);
|
||||||
|
CCC_RETURN_IF_ERROR(symbol_table);
|
||||||
|
if(*symbol_table) {
|
||||||
|
symbol_tables.emplace_back(std::move(*symbol_table));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol_tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::vector<std::unique_ptr<SymbolTable>>> ElfSymbolFile::get_symbol_tables_from_sections(
|
||||||
|
const std::vector<SymbolTableLocation>& sections) const
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<SymbolTable>> symbol_tables;
|
||||||
|
|
||||||
|
for(const SymbolTableLocation& location : sections) {
|
||||||
|
const ElfSection* section = m_elf.lookup_section(location.section_name.c_str());
|
||||||
|
CCC_CHECK(section, "No '%s' section.", location.section_name.c_str());
|
||||||
|
|
||||||
|
Result<std::unique_ptr<SymbolTable>> symbol_table = create_elf_symbol_table(*section, m_elf, location.format);
|
||||||
|
CCC_RETURN_IF_ERROR(symbol_table);
|
||||||
|
if(*symbol_table) {
|
||||||
|
symbol_tables.emplace_back(std::move(*symbol_table));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol_tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ElfFile& ElfSymbolFile::elf() const
|
||||||
|
{
|
||||||
|
return m_elf;
|
||||||
|
}
|
||||||
|
|
||||||
|
SNDLLSymbolFile::SNDLLSymbolFile(std::shared_ptr<SNDLLFile> sndll)
|
||||||
|
: m_sndll(std::move(sndll)) {}
|
||||||
|
|
||||||
|
std::string SNDLLSymbolFile::name() const
|
||||||
|
{
|
||||||
|
return m_sndll->elf_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::vector<std::unique_ptr<SymbolTable>>> SNDLLSymbolFile::get_all_symbol_tables() const
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<SymbolTable>> symbol_tables;
|
||||||
|
symbol_tables.emplace_back(std::make_unique<SNDLLSymbolTable>(m_sndll));
|
||||||
|
return symbol_tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::vector<std::unique_ptr<SymbolTable>>> SNDLLSymbolFile::get_symbol_tables_from_sections(
|
||||||
|
const std::vector<SymbolTableLocation>& sections) const
|
||||||
|
{
|
||||||
|
return CCC_FAILURE("An SNDLL file is not composed of sections.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "elf.h"
|
||||||
|
#include "sndll.h"
|
||||||
|
#include "symbol_table.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
struct SymbolTableLocation {
|
||||||
|
std::string section_name;
|
||||||
|
SymbolTableFormat format;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SymbolFile {
|
||||||
|
public:
|
||||||
|
virtual ~SymbolFile() {}
|
||||||
|
|
||||||
|
virtual std::string name() const = 0;
|
||||||
|
|
||||||
|
virtual Result<std::vector<std::unique_ptr<SymbolTable>>> get_all_symbol_tables() const = 0;
|
||||||
|
virtual Result<std::vector<std::unique_ptr<SymbolTable>>> get_symbol_tables_from_sections(
|
||||||
|
const std::vector<SymbolTableLocation>& sections) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine the type of the input file and parse it.
|
||||||
|
Result<std::unique_ptr<SymbolFile>> parse_symbol_file(std::vector<u8> image, std::string file_name);
|
||||||
|
|
||||||
|
class ElfSymbolFile : public SymbolFile {
|
||||||
|
public:
|
||||||
|
ElfSymbolFile(ElfFile elf, std::string elf_name);
|
||||||
|
|
||||||
|
std::string name() const override;
|
||||||
|
|
||||||
|
Result<std::vector<std::unique_ptr<SymbolTable>>> get_all_symbol_tables() const override;
|
||||||
|
Result<std::vector<std::unique_ptr<SymbolTable>>> get_symbol_tables_from_sections(
|
||||||
|
const std::vector<SymbolTableLocation>& sections) const override;
|
||||||
|
|
||||||
|
const ElfFile& elf() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ElfFile m_elf;
|
||||||
|
std::string m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SNDLLSymbolFile : public SymbolFile {
|
||||||
|
public:
|
||||||
|
SNDLLSymbolFile(std::shared_ptr<SNDLLFile> sndll);
|
||||||
|
|
||||||
|
std::string name() const override;
|
||||||
|
|
||||||
|
Result<std::vector<std::unique_ptr<SymbolTable>>> get_all_symbol_tables() const override;
|
||||||
|
Result<std::vector<std::unique_ptr<SymbolTable>>> get_symbol_tables_from_sections(
|
||||||
|
const std::vector<SymbolTableLocation>& sections) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<SNDLLFile> m_sndll;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,285 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "symbol_table.h"
|
||||||
|
|
||||||
|
#include "elf.h"
|
||||||
|
#include "elf_symtab.h"
|
||||||
|
#include "mdebug_importer.h"
|
||||||
|
#include "mdebug_section.h"
|
||||||
|
#include "sndll.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
const std::vector<SymbolTableFormatInfo> SYMBOL_TABLE_FORMATS = {
|
||||||
|
{MDEBUG, "mdebug", ".mdebug"}, // The infamous Third Eye symbol table.
|
||||||
|
{SYMTAB, "symtab", ".symtab"}, // The standard ELF symbol table.
|
||||||
|
{SNDLL, "sndll", ".sndata"} // The SNDLL symbol table.
|
||||||
|
};
|
||||||
|
|
||||||
|
const SymbolTableFormatInfo* symbol_table_format_from_enum(SymbolTableFormat format)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < SYMBOL_TABLE_FORMATS.size(); i++) {
|
||||||
|
if(SYMBOL_TABLE_FORMATS[i].format == format) {
|
||||||
|
return &SYMBOL_TABLE_FORMATS[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SymbolTableFormatInfo* symbol_table_format_from_name(const char* format_name)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < SYMBOL_TABLE_FORMATS.size(); i++) {
|
||||||
|
if(strcmp(SYMBOL_TABLE_FORMATS[i].format_name, format_name) == 0) {
|
||||||
|
return &SYMBOL_TABLE_FORMATS[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SymbolTableFormatInfo* symbol_table_format_from_section(const char* section_name)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < SYMBOL_TABLE_FORMATS.size(); i++) {
|
||||||
|
if(strcmp(SYMBOL_TABLE_FORMATS[i].section_name, section_name) == 0) {
|
||||||
|
return &SYMBOL_TABLE_FORMATS[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
|
||||||
|
Result<std::unique_ptr<SymbolTable>> create_elf_symbol_table(
|
||||||
|
const ElfSection& section, const ElfFile& elf, SymbolTableFormat format)
|
||||||
|
{
|
||||||
|
std::unique_ptr<SymbolTable> symbol_table;
|
||||||
|
switch(format) {
|
||||||
|
case MDEBUG: {
|
||||||
|
symbol_table = std::make_unique<MdebugSymbolTable>(elf.image, (s32) section.header.offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SYMTAB: {
|
||||||
|
CCC_CHECK(section.header.offset + section.header.size <= elf.image.size(),
|
||||||
|
"Section '%s' out of range.", section.name.c_str());
|
||||||
|
std::span<const u8> data = std::span(elf.image).subspan(section.header.offset, section.header.size);
|
||||||
|
|
||||||
|
CCC_CHECK(section.header.link != 0, "Section '%s' has no linked string table.", section.name.c_str());
|
||||||
|
CCC_CHECK(section.header.link < elf.sections.size(),
|
||||||
|
"Section '%s' has out of range link field.", section.name.c_str());
|
||||||
|
const ElfSection& linked_section = elf.sections[section.header.link];
|
||||||
|
|
||||||
|
CCC_CHECK(linked_section.header.offset + linked_section.header.size <= elf.image.size(),
|
||||||
|
"Linked section '%s' out of range.", linked_section.name.c_str());
|
||||||
|
std::span<const u8> linked_data = std::span(elf.image).subspan(
|
||||||
|
linked_section.header.offset, linked_section.header.size);
|
||||||
|
|
||||||
|
symbol_table = std::make_unique<SymtabSymbolTable>(data, linked_data);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SNDLL: {
|
||||||
|
CCC_CHECK(section.header.offset + section.header.size <= elf.image.size(),
|
||||||
|
"Section '%s' out of range.", section.name.c_str());
|
||||||
|
std::span<const u8> data = std::span(elf.image).subspan(section.header.offset, section.header.size);
|
||||||
|
|
||||||
|
if(data.size() >= 4 && data[0] != '\0') {
|
||||||
|
Result<SNDLLFile> file = parse_sndll_file(data, Address::non_zero(section.header.addr), SNDLLType::SNDATA_SECTION);
|
||||||
|
CCC_RETURN_IF_ERROR(file);
|
||||||
|
|
||||||
|
symbol_table = std::make_unique<SNDLLSymbolTable>(std::make_shared<SNDLLFile>(std::move(*file)));
|
||||||
|
} else {
|
||||||
|
CCC_WARN("Invalid SNDLL section.");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ModuleHandle> import_symbol_tables(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const std::vector<std::unique_ptr<SymbolTable>>& symbol_tables,
|
||||||
|
std::string module_name,
|
||||||
|
Address base_address,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt)
|
||||||
|
{
|
||||||
|
Result<SymbolSourceHandle> module_source = database.get_symbol_source("Symbol Table Importer");
|
||||||
|
CCC_RETURN_IF_ERROR(module_source);
|
||||||
|
|
||||||
|
Result<Module*> module_symbol = database.modules.create_symbol(
|
||||||
|
std::move(module_name), base_address, *module_source, nullptr);
|
||||||
|
CCC_RETURN_IF_ERROR(module_symbol);
|
||||||
|
|
||||||
|
ModuleHandle module_handle = (*module_symbol)->handle();
|
||||||
|
|
||||||
|
for(const std::unique_ptr<SymbolTable>& symbol_table : symbol_tables) {
|
||||||
|
// Find a symbol source object with the right name, or create one if one
|
||||||
|
// doesn't already exist.
|
||||||
|
Result<SymbolSourceHandle> source = database.get_symbol_source(symbol_table->name());
|
||||||
|
if(!source.success()) {
|
||||||
|
database.destroy_symbols_from_module(module_handle, false);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import the symbol table.
|
||||||
|
SymbolGroup group;
|
||||||
|
group.source = *source;
|
||||||
|
group.module_symbol = database.modules.symbol_from_handle(module_handle);
|
||||||
|
|
||||||
|
Result<void> result = symbol_table->import(
|
||||||
|
database, group, importer_flags, demangler, interrupt);
|
||||||
|
if(!result.success()) {
|
||||||
|
database.destroy_symbols_from_module(module_handle, false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return module_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
|
||||||
|
MdebugSymbolTable::MdebugSymbolTable(std::span<const u8> image, s32 section_offset)
|
||||||
|
: m_image(image), m_section_offset(section_offset) {}
|
||||||
|
|
||||||
|
const char* MdebugSymbolTable::name() const
|
||||||
|
{
|
||||||
|
return "MIPS Debug Symbol Table";
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> MdebugSymbolTable::import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const
|
||||||
|
{
|
||||||
|
return mdebug::import_symbol_table(
|
||||||
|
database, m_image, m_section_offset, group, importer_flags, demangler, interrupt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> MdebugSymbolTable::print_headers(FILE* out) const
|
||||||
|
{
|
||||||
|
mdebug::SymbolTableReader reader;
|
||||||
|
|
||||||
|
Result<void> reader_result = reader.init(m_image, m_section_offset);
|
||||||
|
CCC_RETURN_IF_ERROR(reader_result);
|
||||||
|
|
||||||
|
reader.print_header(out);
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> MdebugSymbolTable::print_symbols(FILE* out, u32 flags) const
|
||||||
|
{
|
||||||
|
mdebug::SymbolTableReader reader;
|
||||||
|
Result<void> reader_result = reader.init(m_image, m_section_offset);
|
||||||
|
CCC_RETURN_IF_ERROR(reader_result);
|
||||||
|
|
||||||
|
Result<void> print_result = reader.print_symbols(
|
||||||
|
out, flags & PRINT_LOCALS, flags & PRINT_PROCEDURE_DESCRIPTORS, flags & PRINT_EXTERNALS);
|
||||||
|
CCC_RETURN_IF_ERROR(print_result);
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
|
||||||
|
SymtabSymbolTable::SymtabSymbolTable(std::span<const u8> symtab, std::span<const u8> strtab)
|
||||||
|
: m_symtab(symtab), m_strtab(strtab) {}
|
||||||
|
|
||||||
|
const char* SymtabSymbolTable::name() const
|
||||||
|
{
|
||||||
|
return "ELF Symbol Table";
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> SymtabSymbolTable::import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const
|
||||||
|
{
|
||||||
|
return elf::import_symbols(database, group, m_symtab, m_strtab, importer_flags, demangler);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> SymtabSymbolTable::print_headers(FILE* out) const
|
||||||
|
{
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> SymtabSymbolTable::print_symbols(FILE* out, u32 flags) const
|
||||||
|
{
|
||||||
|
Result<void> symbtab_result = elf::print_symbol_table(out, m_symtab, m_strtab);
|
||||||
|
CCC_RETURN_IF_ERROR(symbtab_result);
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
|
||||||
|
SNDLLSymbolTable::SNDLLSymbolTable(std::shared_ptr<SNDLLFile> sndll)
|
||||||
|
: m_sndll(std::move(sndll)) {}
|
||||||
|
|
||||||
|
const char* SNDLLSymbolTable::name() const
|
||||||
|
{
|
||||||
|
return "SNDLL Symbol Table";
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> SNDLLSymbolTable::import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const
|
||||||
|
{
|
||||||
|
return import_sndll_symbols(database, *m_sndll, group, importer_flags, demangler);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> SNDLLSymbolTable::print_headers(FILE* out) const
|
||||||
|
{
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> SNDLLSymbolTable::print_symbols(FILE* out, u32 flags) const
|
||||||
|
{
|
||||||
|
print_sndll_symbols(out, *m_sndll);
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
|
||||||
|
ElfSectionHeadersSymbolTable::ElfSectionHeadersSymbolTable(const ElfFile& elf)
|
||||||
|
: m_elf(elf) {}
|
||||||
|
|
||||||
|
const char* ElfSectionHeadersSymbolTable::name() const
|
||||||
|
{
|
||||||
|
return "ELF Section Headers";
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> ElfSectionHeadersSymbolTable::import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const
|
||||||
|
{
|
||||||
|
return m_elf.create_section_symbols(database, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> ElfSectionHeadersSymbolTable::print_headers(FILE* out) const
|
||||||
|
{
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> ElfSectionHeadersSymbolTable::print_symbols(FILE* out, u32 flags) const
|
||||||
|
{
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "symbol_database.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
// Determine which symbol tables are present in a given file.
|
||||||
|
|
||||||
|
enum SymbolTableFormat {
|
||||||
|
MDEBUG = 0, // The infamous Third Eye symbol table
|
||||||
|
SYMTAB = 1, // Standard ELF symbol table
|
||||||
|
SNDLL = 2 // SNDLL section
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SymbolTableFormatInfo {
|
||||||
|
SymbolTableFormat format;
|
||||||
|
const char* format_name;
|
||||||
|
const char* section_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
// All the supported symbol table formats, sorted from best to worst.
|
||||||
|
extern const std::vector<SymbolTableFormatInfo> SYMBOL_TABLE_FORMATS;
|
||||||
|
|
||||||
|
const SymbolTableFormatInfo* symbol_table_format_from_enum(SymbolTableFormat format);
|
||||||
|
const SymbolTableFormatInfo* symbol_table_format_from_name(const char* format_name);
|
||||||
|
const SymbolTableFormatInfo* symbol_table_format_from_section(const char* section_name);
|
||||||
|
|
||||||
|
enum SymbolPrintFlags {
|
||||||
|
PRINT_LOCALS = 1 << 0,
|
||||||
|
PRINT_PROCEDURE_DESCRIPTORS = 1 << 1,
|
||||||
|
PRINT_EXTERNALS = 1 << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
class SymbolTable {
|
||||||
|
public:
|
||||||
|
virtual ~SymbolTable() {}
|
||||||
|
|
||||||
|
virtual const char* name() const = 0;
|
||||||
|
|
||||||
|
// Imports this symbol table into the passed database.
|
||||||
|
virtual Result<void> import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const = 0;
|
||||||
|
|
||||||
|
// Print out all the field in the header structure if one exists.
|
||||||
|
virtual Result<void> print_headers(FILE* out) const = 0;
|
||||||
|
|
||||||
|
// Print out all the symbols in the symbol table. For .mdebug symbol tables
|
||||||
|
// the symbols are split between those that are local to a specific
|
||||||
|
// translation unit and those that are external, which is what the
|
||||||
|
// print_locals and print_externals parameters control.
|
||||||
|
virtual Result<void> print_symbols(FILE* out, u32 flags) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ElfSection;
|
||||||
|
struct ElfFile;
|
||||||
|
|
||||||
|
// Create a symbol table from an ELF section. The return value may be null.
|
||||||
|
Result<std::unique_ptr<SymbolTable>> create_elf_symbol_table(
|
||||||
|
const ElfSection& section, const ElfFile& elf, SymbolTableFormat format);
|
||||||
|
|
||||||
|
// Utility function to call import_symbol_table on all the passed symbol tables
|
||||||
|
// and to generate a module handle.
|
||||||
|
Result<ModuleHandle> import_symbol_tables(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const std::vector<std::unique_ptr<SymbolTable>>& symbol_tables,
|
||||||
|
std::string module_name,
|
||||||
|
Address base_address,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt);
|
||||||
|
|
||||||
|
class MdebugSymbolTable : public SymbolTable {
|
||||||
|
public:
|
||||||
|
MdebugSymbolTable(std::span<const u8> image, s32 section_offset);
|
||||||
|
|
||||||
|
const char* name() const override;
|
||||||
|
|
||||||
|
Result<void> import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const override;
|
||||||
|
|
||||||
|
Result<void> print_headers(FILE* out) const override;
|
||||||
|
Result<void> print_symbols(FILE* out, u32 flags) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::span<const u8> m_image;
|
||||||
|
s32 m_section_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SymtabSymbolTable : public SymbolTable {
|
||||||
|
public:
|
||||||
|
SymtabSymbolTable(std::span<const u8> symtab, std::span<const u8> strtab);
|
||||||
|
|
||||||
|
const char* name() const override;
|
||||||
|
|
||||||
|
Result<void> import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const override;
|
||||||
|
|
||||||
|
Result<void> print_headers(FILE* out) const override;
|
||||||
|
Result<void> print_symbols(FILE* out, u32 flags) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::span<const u8> m_symtab;
|
||||||
|
std::span<const u8> m_strtab;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SNDLLFile;
|
||||||
|
|
||||||
|
class SNDLLSymbolTable : public SymbolTable {
|
||||||
|
public:
|
||||||
|
SNDLLSymbolTable(std::shared_ptr<SNDLLFile> sndll);
|
||||||
|
|
||||||
|
const char* name() const override;
|
||||||
|
|
||||||
|
Result<void> import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const override;
|
||||||
|
|
||||||
|
Result<void> print_headers(FILE* out) const override;
|
||||||
|
Result<void> print_symbols(FILE* out, u32 flags) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<SNDLLFile> m_sndll;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ElfSectionHeadersSymbolTable : public SymbolTable {
|
||||||
|
public:
|
||||||
|
ElfSectionHeadersSymbolTable(const ElfFile& elf);
|
||||||
|
|
||||||
|
const char* name() const override;
|
||||||
|
|
||||||
|
Result<void> import(
|
||||||
|
SymbolDatabase& database,
|
||||||
|
const SymbolGroup& group,
|
||||||
|
u32 importer_flags,
|
||||||
|
DemanglerFunctions demangler,
|
||||||
|
const std::atomic_bool* interrupt) const override;
|
||||||
|
|
||||||
|
Result<void> print_headers(FILE* out) const override;
|
||||||
|
Result<void> print_symbols(FILE* out, u32 flags) const override;
|
||||||
|
protected:
|
||||||
|
const ElfFile& m_elf;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
static CustomErrorCallback custom_error_callback = nullptr;
|
||||||
|
|
||||||
|
Error format_error(const char* source_file, int source_line, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
char message[4096];
|
||||||
|
if(vsnprintf(message, sizeof(message), format, args) < 0) {
|
||||||
|
strncpy(message, "Failed to generate error message.", sizeof(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
Error error;
|
||||||
|
error.message = message;
|
||||||
|
error.source_file = source_file;
|
||||||
|
error.source_line = source_line;
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void report_error(const Error& error)
|
||||||
|
{
|
||||||
|
if(custom_error_callback) {
|
||||||
|
custom_error_callback(error, ERROR_LEVEL_ERROR);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "[%s:%d] " CCC_ANSI_COLOUR_RED "error:" CCC_ANSI_COLOUR_OFF " %s\n",
|
||||||
|
error.source_file, error.source_line, error.message.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void report_warning(const Error& warning)
|
||||||
|
{
|
||||||
|
if(custom_error_callback) {
|
||||||
|
custom_error_callback(warning, ERROR_LEVEL_WARNING);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "[%s:%d] " CCC_ANSI_COLOUR_MAGENTA "warning:" CCC_ANSI_COLOUR_OFF " %s\n",
|
||||||
|
warning.source_file, warning.source_line, warning.message.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_custom_error_callback(CustomErrorCallback callback)
|
||||||
|
{
|
||||||
|
custom_error_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string_view> get_string(std::span<const u8> bytes, u64 offset)
|
||||||
|
{
|
||||||
|
for(u64 i = offset; i < bytes.size(); i++) {
|
||||||
|
if(bytes[i] == '\0') {
|
||||||
|
return std::string_view(
|
||||||
|
reinterpret_cast<const char*>(&bytes[offset]),
|
||||||
|
reinterpret_cast<const char*>(&bytes[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string merge_paths(const std::string& base, const std::string& path)
|
||||||
|
{
|
||||||
|
// Try to figure out if we're dealing with a Windows path of a UNIX path.
|
||||||
|
bool is_windows_path = false;
|
||||||
|
if(base.empty()) {
|
||||||
|
is_windows_path = guess_is_windows_path(path.c_str());
|
||||||
|
} else {
|
||||||
|
is_windows_path = guess_is_windows_path(base.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually merge the paths. If path is the entire path, we don't need to
|
||||||
|
// append base onto the front, so check for that now.
|
||||||
|
bool is_absolute_unix = (path.size() >= 1) && (path[0] == '/' || path[0] == '\\');
|
||||||
|
bool is_absolute_windows = (path.size() >= 3) && path[1] == ':' && (path[2] == '/' || path[2] == '\\');
|
||||||
|
if(base.empty() || is_absolute_unix || is_absolute_windows) {
|
||||||
|
return normalise_path(path.c_str(), is_windows_path);
|
||||||
|
}
|
||||||
|
return normalise_path((base + "/" + path).c_str(), is_windows_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string normalise_path(const char* input, bool use_backslashes_as_path_separators)
|
||||||
|
{
|
||||||
|
bool is_absolute = false;
|
||||||
|
std::optional<char> drive_letter;
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
|
||||||
|
// Parse the beginning of the path.
|
||||||
|
if(*input == '/' || *input == '\\') { // UNIX path, drive relative Windows path or UNC Windows path.
|
||||||
|
is_absolute = true;
|
||||||
|
} else if(isalpha(*input) && input[1] == ':' && (input[2] == '/' || input[2] == '\\')) { // Absolute Windows path.
|
||||||
|
is_absolute = true;
|
||||||
|
drive_letter = toupper(*input);
|
||||||
|
input += 2;
|
||||||
|
} else {
|
||||||
|
parts.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the rest of the path.
|
||||||
|
while(*input != 0) {
|
||||||
|
if(*input == '/' || *input == '\\') {
|
||||||
|
while(*input == '/' || *input == '\\') input++;
|
||||||
|
parts.emplace_back();
|
||||||
|
} else {
|
||||||
|
parts.back() += *(input++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove "." and ".." parts.
|
||||||
|
for(s32 i = 0; i < (s32) parts.size(); i++) {
|
||||||
|
if(parts[i] == ".") {
|
||||||
|
parts.erase(parts.begin() + i);
|
||||||
|
i--;
|
||||||
|
} else if(parts[i] == ".." && i > 0 && parts[i - 1] != "..") {
|
||||||
|
parts.erase(parts.begin() + i);
|
||||||
|
parts.erase(parts.begin() + i - 1);
|
||||||
|
i -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output the path in a normal form.
|
||||||
|
std::string output;
|
||||||
|
if(is_absolute) {
|
||||||
|
if(drive_letter.has_value()) {
|
||||||
|
output += *drive_letter;
|
||||||
|
output += ":";
|
||||||
|
}
|
||||||
|
output += use_backslashes_as_path_separators ? '\\' : '/';
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < parts.size(); i++) {
|
||||||
|
output += parts[i];
|
||||||
|
if(i != parts.size() - 1) {
|
||||||
|
output += use_backslashes_as_path_separators ? '\\' : '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool guess_is_windows_path(const char* path)
|
||||||
|
{
|
||||||
|
for(const char* ptr = path; *ptr != 0; ptr++) {
|
||||||
|
if(*ptr == '\\') {
|
||||||
|
return true;
|
||||||
|
} else if(*ptr == '/') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string extract_file_name(const std::string& path)
|
||||||
|
{
|
||||||
|
std::string::size_type forward_pos = path.find_last_of('/');
|
||||||
|
std::string::size_type backward_pos = path.find_last_of('\\');
|
||||||
|
std::string::size_type pos;
|
||||||
|
if(forward_pos == std::string::npos) {
|
||||||
|
pos = backward_pos;
|
||||||
|
} else if(backward_pos == std::string::npos) {
|
||||||
|
pos = forward_pos;
|
||||||
|
} else {
|
||||||
|
pos = std::max(forward_pos, backward_pos);
|
||||||
|
}
|
||||||
|
if(pos + 1 != path.size() && pos != std::string::npos) {
|
||||||
|
return path.substr(pos + 1);
|
||||||
|
} else {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,341 @@
|
||||||
|
// This file is part of the Chaos Compiler Collection.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <span>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace ccc {
|
||||||
|
|
||||||
|
using u8 = unsigned char;
|
||||||
|
using u16 = uint16_t;
|
||||||
|
using u32 = uint32_t;
|
||||||
|
using u64 = uint64_t;
|
||||||
|
|
||||||
|
using s8 = signed char;
|
||||||
|
using s16 = int16_t;
|
||||||
|
using s32 = int32_t;
|
||||||
|
using s64 = int64_t;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define CCC_ANSI_COLOUR_OFF ""
|
||||||
|
#define CCC_ANSI_COLOUR_RED ""
|
||||||
|
#define CCC_ANSI_COLOUR_MAGENTA ""
|
||||||
|
#define CCC_ANSI_COLOUR_GRAY ""
|
||||||
|
#else
|
||||||
|
#define CCC_ANSI_COLOUR_OFF "\033[0m"
|
||||||
|
#define CCC_ANSI_COLOUR_RED "\033[31m"
|
||||||
|
#define CCC_ANSI_COLOUR_MAGENTA "\033[35m"
|
||||||
|
#define CCC_ANSI_COLOUR_GRAY "\033[90m"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Error {
|
||||||
|
std::string message;
|
||||||
|
const char* source_file;
|
||||||
|
s32 source_line;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ErrorLevel {
|
||||||
|
ERROR_LEVEL_ERROR,
|
||||||
|
ERROR_LEVEL_WARNING
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*CustomErrorCallback)(const Error& error, ErrorLevel level);
|
||||||
|
|
||||||
|
Error format_error(const char* source_file, int source_line, const char* format, ...);
|
||||||
|
void report_error(const Error& error);
|
||||||
|
void report_warning(const Error& warning);
|
||||||
|
void set_custom_error_callback(CustomErrorCallback callback);
|
||||||
|
|
||||||
|
#define CCC_FATAL(...) \
|
||||||
|
{ \
|
||||||
|
ccc::Error error = ccc::format_error(__FILE__, __LINE__, __VA_ARGS__); \
|
||||||
|
ccc::report_error(error); \
|
||||||
|
exit(1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CCC_CHECK_FATAL(condition, ...) \
|
||||||
|
if(!(condition)) { \
|
||||||
|
ccc::Error error = ccc::format_error(__FILE__, __LINE__, __VA_ARGS__); \
|
||||||
|
ccc::report_error(error); \
|
||||||
|
exit(1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CCC_ABORT_IF_FALSE(condition, ...) \
|
||||||
|
if(!(condition)) { \
|
||||||
|
ccc::Error error = ccc::format_error(__FILE__, __LINE__, __VA_ARGS__); \
|
||||||
|
ccc::report_error(error); \
|
||||||
|
abort(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CCC_ASSERT(condition) \
|
||||||
|
CCC_ABORT_IF_FALSE(condition, #condition)
|
||||||
|
|
||||||
|
// The main error handling construct in CCC. This class is used to bundle
|
||||||
|
// together a return value and a pointer to error information, so that errors
|
||||||
|
// can be propagated up the stack.
|
||||||
|
template <typename Value>
|
||||||
|
class [[nodiscard]] Result {
|
||||||
|
template <typename OtherValue>
|
||||||
|
friend class Result;
|
||||||
|
protected:
|
||||||
|
Value m_value;
|
||||||
|
std::unique_ptr<Error> m_error;
|
||||||
|
|
||||||
|
Result() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Result(Value value) : m_value(std::move(value)), m_error(nullptr) {}
|
||||||
|
|
||||||
|
// Used to propagate errors up the call stack.
|
||||||
|
template <typename OtherValue>
|
||||||
|
Result(Result<OtherValue>&& rhs)
|
||||||
|
{
|
||||||
|
CCC_ASSERT(rhs.m_error != nullptr);
|
||||||
|
m_error = std::move(rhs.m_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<Value> failure(Error error)
|
||||||
|
{
|
||||||
|
Result<Value> result;
|
||||||
|
result.m_error = std::make_unique<Error>(std::move(error));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success() const
|
||||||
|
{
|
||||||
|
return m_error == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Error& error() const
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_error != nullptr);
|
||||||
|
return *m_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value& operator*()
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_error == nullptr);
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Value& operator*() const
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_error == nullptr);
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* operator->()
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_error == nullptr);
|
||||||
|
return &m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Value* operator->() const
|
||||||
|
{
|
||||||
|
CCC_ASSERT(m_error == nullptr);
|
||||||
|
return &m_value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class [[nodiscard]] Result<void> : public Result<int> {
|
||||||
|
public:
|
||||||
|
Result() : Result<int>(0) {}
|
||||||
|
|
||||||
|
// Used to propagate errors up the call stack.
|
||||||
|
template <typename OtherValue>
|
||||||
|
Result(Result<OtherValue>&& rhs)
|
||||||
|
{
|
||||||
|
CCC_ASSERT(rhs.m_error != nullptr);
|
||||||
|
m_error = std::move(rhs.m_error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CCC_FAILURE(...) ccc::Result<int>::failure(ccc::format_error(__FILE__, __LINE__, __VA_ARGS__))
|
||||||
|
|
||||||
|
#define CCC_CHECK(condition, ...) \
|
||||||
|
if(!(condition)) { \
|
||||||
|
return CCC_FAILURE(__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CCC_EXPECT_CHAR(input, c, context) \
|
||||||
|
CCC_CHECK(*(input++) == c, \
|
||||||
|
"Expected '%c' in %s, got '%c' (%02hhx)", \
|
||||||
|
c, context, *(input - 1), *(input - 1))
|
||||||
|
|
||||||
|
#define CCC_RETURN_IF_ERROR(result) \
|
||||||
|
if(!(result).success()) { \
|
||||||
|
return (result); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CCC_EXIT_IF_ERROR(result) \
|
||||||
|
if(!(result).success()) { \
|
||||||
|
ccc::report_error((result).error()); \
|
||||||
|
exit(1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CCC_GTEST_FAIL_IF_ERROR(result) \
|
||||||
|
if(!(result).success()) { \
|
||||||
|
FAIL() << (result).error().message; \
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void warn_impl(const char* source_file, int source_line, const char* format, Args... args)
|
||||||
|
{
|
||||||
|
Error warning = format_error(source_file, source_line, format, args...);
|
||||||
|
report_warning(warning);
|
||||||
|
}
|
||||||
|
#define CCC_WARN(...) \
|
||||||
|
ccc::warn_impl(__FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define CCC_PACKED_STRUCT(name, ...) \
|
||||||
|
__pragma(pack(push, 1)) struct name { __VA_ARGS__ } __pragma(pack(pop));
|
||||||
|
#else
|
||||||
|
#define CCC_PACKED_STRUCT(name, ...) \
|
||||||
|
struct __attribute__((__packed__)) name { __VA_ARGS__ };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T* get_aligned(std::span<const u8> bytes, u64 offset)
|
||||||
|
{
|
||||||
|
if(offset > bytes.size() || bytes.size() - offset < sizeof(T) || offset % alignof(T) != 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reinterpret_cast<const T*>(&bytes[offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T* get_unaligned(std::span<const u8> bytes, u64 offset)
|
||||||
|
{
|
||||||
|
if(offset > bytes.size() || bytes.size() - offset < sizeof(T)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reinterpret_cast<const T*>(&bytes[offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T> copy_unaligned(std::span<const u8> bytes, u64 offset)
|
||||||
|
{
|
||||||
|
if(offset > bytes.size() || bytes.size() - offset < sizeof(T)) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
T value;
|
||||||
|
memcpy(&value, &bytes[offset], sizeof(T));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string_view> get_string(std::span<const u8> bytes, u64 offset);
|
||||||
|
|
||||||
|
#define CCC_BEGIN_END(x) (x).begin(), (x).end()
|
||||||
|
#define CCC_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
||||||
|
#define CCC_FOURCC(string) ((string)[0] | (string)[1] << 8 | (string)[2] << 16 | (string)[3] << 24)
|
||||||
|
|
||||||
|
struct Address {
|
||||||
|
u32 value = (u32) -1;
|
||||||
|
|
||||||
|
Address() {}
|
||||||
|
Address(u32 v) : value(v) {}
|
||||||
|
|
||||||
|
bool valid() const
|
||||||
|
{
|
||||||
|
return value != (u32) -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 get_or_zero() const
|
||||||
|
{
|
||||||
|
if(valid()) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Address add_base_address(Address base_address) const
|
||||||
|
{
|
||||||
|
if(valid()) {
|
||||||
|
return base_address.get_or_zero() + value;
|
||||||
|
} else {
|
||||||
|
return Address();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Address non_zero(u32 address)
|
||||||
|
{
|
||||||
|
Address result;
|
||||||
|
if(address != 0) {
|
||||||
|
result = address;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend auto operator<=>(const Address& lhs, const Address& rhs) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AddressRange {
|
||||||
|
Address low;
|
||||||
|
Address high;
|
||||||
|
|
||||||
|
AddressRange() {}
|
||||||
|
AddressRange(Address address) : low(address), high(address) {}
|
||||||
|
AddressRange(Address l, Address h) : low(l), high(h) {}
|
||||||
|
|
||||||
|
friend auto operator<=>(const AddressRange& lhs, const AddressRange& rhs) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
// These functions are to be used only for source file paths present in the
|
||||||
|
// symbol table, since we want them to be handled consistently across different
|
||||||
|
// platforms, which with std::filesystem::path doesn't seem to be possible.
|
||||||
|
std::string merge_paths(const std::string& base, const std::string& path);
|
||||||
|
std::string normalise_path(const char* input, bool use_backslashes_as_path_separators);
|
||||||
|
bool guess_is_windows_path(const char* path);
|
||||||
|
std::string extract_file_name(const std::string& path);
|
||||||
|
|
||||||
|
namespace ast { struct Node; }
|
||||||
|
|
||||||
|
// These are used to reference STABS types from other types within a single
|
||||||
|
// translation unit. For most games these will just be a single number, the type
|
||||||
|
// number. In some cases, for example with the homebrew SDK, type numbers are a
|
||||||
|
// pair of two numbers surrounded by round brackets e.g. (1,23) where the first
|
||||||
|
// number is the index of the include file to use (includes are listed for each
|
||||||
|
// translation unit separately), and the second number is the type number.
|
||||||
|
struct StabsTypeNumber {
|
||||||
|
s32 file = -1;
|
||||||
|
s32 type = -1;
|
||||||
|
|
||||||
|
friend auto operator<=>(const StabsTypeNumber& lhs, const StabsTypeNumber& rhs) = default;
|
||||||
|
bool valid() const { return type > -1; }
|
||||||
|
};
|
||||||
|
|
||||||
|
enum StorageClass {
|
||||||
|
STORAGE_CLASS_NONE = 0,
|
||||||
|
STORAGE_CLASS_TYPEDEF = 1,
|
||||||
|
STORAGE_CLASS_EXTERN = 2,
|
||||||
|
STORAGE_CLASS_STATIC = 3,
|
||||||
|
STORAGE_CLASS_AUTO = 4,
|
||||||
|
STORAGE_CLASS_REGISTER = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function pointers for the GNU demangler functions, so we can build CCC as a
|
||||||
|
// library without linking against the demangler.
|
||||||
|
struct DemanglerFunctions {
|
||||||
|
char* (*cplus_demangle)(const char *mangled, int options) = nullptr;
|
||||||
|
char* (*cplus_demangle_opname)(const char *opname, int options) = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.5 FATAL_ERROR)
|
||||||
# ---[ Setup project
|
# ---[ Setup project
|
||||||
PROJECT(
|
PROJECT(
|
||||||
cpuinfo
|
cpuinfo
|
||||||
LANGUAGES C CXX
|
LANGUAGES C
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---[ Options.
|
# ---[ Options.
|
||||||
|
@ -13,6 +13,26 @@ SET(CPUINFO_RUNTIME_TYPE "default" CACHE STRING "Type of runtime library (shared
|
||||||
SET_PROPERTY(CACHE CPUINFO_RUNTIME_TYPE PROPERTY STRINGS default static shared)
|
SET_PROPERTY(CACHE CPUINFO_RUNTIME_TYPE PROPERTY STRINGS default static shared)
|
||||||
SET(CPUINFO_LOG_LEVEL "default" CACHE STRING "Minimum logging level (info with lower severity will be ignored)")
|
SET(CPUINFO_LOG_LEVEL "default" CACHE STRING "Minimum logging level (info with lower severity will be ignored)")
|
||||||
SET_PROPERTY(CACHE CPUINFO_LOG_LEVEL PROPERTY STRINGS default debug info warning error fatal none)
|
SET_PROPERTY(CACHE CPUINFO_LOG_LEVEL PROPERTY STRINGS default debug info warning error fatal none)
|
||||||
|
IF(ANDROID)
|
||||||
|
OPTION(CPUINFO_LOG_TO_STDIO "Log errors, warnings, and information to stdout/stderr" OFF)
|
||||||
|
ELSE()
|
||||||
|
OPTION(CPUINFO_LOG_TO_STDIO "Log errors, warnings, and information to stdout/stderr" ON)
|
||||||
|
ENDIF()
|
||||||
|
OPTION(CPUINFO_BUILD_TOOLS "Build command-line tools" OFF)
|
||||||
|
OPTION(CPUINFO_BUILD_UNIT_TESTS "Build cpuinfo unit tests" OFF)
|
||||||
|
OPTION(CPUINFO_BUILD_MOCK_TESTS "Build cpuinfo mock tests" OFF)
|
||||||
|
OPTION(CPUINFO_BUILD_BENCHMARKS "Build cpuinfo micro-benchmarks" OFF)
|
||||||
|
OPTION(CPUINFO_BUILD_PKG_CONFIG "Build pkg-config manifest" OFF)
|
||||||
|
OPTION(USE_SYSTEM_LIBS "Use system libraries instead of downloading and building them" OFF)
|
||||||
|
OPTION(USE_SYSTEM_GOOGLEBENCHMARK "Use system Google Benchmark library instead of downloading and building it" ${USE_SYSTEM_LIBS})
|
||||||
|
OPTION(USE_SYSTEM_GOOGLETEST "Use system Google Test library instead of downloading and building it" ${USE_SYSTEM_LIBS})
|
||||||
|
|
||||||
|
# ---[ CMake options
|
||||||
|
INCLUDE(GNUInstallDirs)
|
||||||
|
|
||||||
|
IF(CPUINFO_BUILD_UNIT_TESTS OR CPUINFO_BUILD_MOCK_TESTS)
|
||||||
|
ENABLE_TESTING()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
MACRO(CPUINFO_TARGET_ENABLE_C99 target)
|
MACRO(CPUINFO_TARGET_ENABLE_C99 target)
|
||||||
SET_TARGET_PROPERTIES(${target} PROPERTIES
|
SET_TARGET_PROPERTIES(${target} PROPERTIES
|
||||||
|
@ -22,7 +42,7 @@ ENDMACRO()
|
||||||
|
|
||||||
MACRO(CPUINFO_TARGET_ENABLE_CXX11 target)
|
MACRO(CPUINFO_TARGET_ENABLE_CXX11 target)
|
||||||
SET_TARGET_PROPERTIES(${target} PROPERTIES
|
SET_TARGET_PROPERTIES(${target} PROPERTIES
|
||||||
CXX_STANDARD 11
|
CXX_STANDARD 14
|
||||||
CXX_EXTENSIONS NO)
|
CXX_EXTENSIONS NO)
|
||||||
ENDMACRO()
|
ENDMACRO()
|
||||||
|
|
||||||
|
@ -38,10 +58,32 @@ MACRO(CPUINFO_TARGET_RUNTIME_LIBRARY target)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDMACRO()
|
ENDMACRO()
|
||||||
|
|
||||||
|
# -- [ Determine whether building for Apple's desktop or mobile OSes
|
||||||
|
IF(CMAKE_SYSTEM_NAME MATCHES "^(Darwin|iOS|tvOS|watchOS)$")
|
||||||
|
SET(IS_APPLE_OS TRUE)
|
||||||
|
ELSE()
|
||||||
|
SET(IS_APPLE_OS FALSE)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
# -- [ Determine target processor
|
# -- [ Determine target processor
|
||||||
SET(CPUINFO_TARGET_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}")
|
SET(CPUINFO_TARGET_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}")
|
||||||
IF(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_ARCHITECTURES MATCHES "^(x86_64|arm64)$")
|
IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD" AND CPUINFO_TARGET_PROCESSOR STREQUAL "amd64")
|
||||||
|
SET(CPUINFO_TARGET_PROCESSOR "AMD64")
|
||||||
|
ENDIF()
|
||||||
|
IF(IS_APPLE_OS AND CMAKE_OSX_ARCHITECTURES MATCHES "^(x86_64|arm64.*)$")
|
||||||
SET(CPUINFO_TARGET_PROCESSOR "${CMAKE_OSX_ARCHITECTURES}")
|
SET(CPUINFO_TARGET_PROCESSOR "${CMAKE_OSX_ARCHITECTURES}")
|
||||||
|
ELSEIF(CMAKE_GENERATOR MATCHES "^Visual Studio " AND CMAKE_VS_PLATFORM_NAME)
|
||||||
|
IF(CMAKE_VS_PLATFORM_NAME STREQUAL "Win32")
|
||||||
|
SET(CPUINFO_TARGET_PROCESSOR "x86")
|
||||||
|
ELSEIF(CMAKE_VS_PLATFORM_NAME STREQUAL "x64")
|
||||||
|
SET(CPUINFO_TARGET_PROCESSOR "x86_64")
|
||||||
|
ELSEIF(CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64")
|
||||||
|
SET(CPUINFO_TARGET_PROCESSOR "arm64")
|
||||||
|
ELSEIF(CMAKE_VS_PLATFORM_NAME MATCHES "^(ARM64EC|arm64ec|ARM64E|arm64e)")
|
||||||
|
SET(CPUINFO_TARGET_PROCESSOR "arm64")
|
||||||
|
ELSE()
|
||||||
|
MESSAGE(FATAL_ERROR "Unsupported Visual Studio architecture \"${CMAKE_VS_PLATFORM_NAME}\"")
|
||||||
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
# ---[ Build flags
|
# ---[ Build flags
|
||||||
|
@ -53,20 +95,21 @@ IF(NOT CMAKE_SYSTEM_PROCESSOR)
|
||||||
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
|
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
|
||||||
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
|
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ELSEIF(NOT CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?|armv[5-8].*|aarch64|arm64)$")
|
ELSEIF(NOT CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?|armv[5-8].*|aarch64|arm64.*|ARM64.*|riscv(32|64))$")
|
||||||
MESSAGE(WARNING
|
MESSAGE(WARNING
|
||||||
"Target processor architecture \"${CPUINFO_TARGET_PROCESSOR}\" is not supported in cpuinfo. "
|
"Target processor architecture \"${CPUINFO_TARGET_PROCESSOR}\" is not supported in cpuinfo. "
|
||||||
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
|
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
|
||||||
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
|
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
|
||||||
IF(NOT CMAKE_SYSTEM_NAME)
|
IF(NOT CMAKE_SYSTEM_NAME)
|
||||||
MESSAGE(WARNING
|
MESSAGE(WARNING
|
||||||
"Target operating system is not specified. "
|
"Target operating system is not specified. "
|
||||||
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
|
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
|
||||||
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
|
SET(CPUINFO_SUPPORTED_PLATFORM FALSE)
|
||||||
ELSEIF(NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN|MSYS|Darwin|Linux|Android)$")
|
ELSEIF(NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|WindowsStore|CYGWIN|MSYS|Darwin|Linux|Android|FreeBSD)$")
|
||||||
IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14" AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14" AND NOT IS_APPLE_OS)
|
||||||
MESSAGE(WARNING
|
MESSAGE(WARNING
|
||||||
"Target operating system \"${CMAKE_SYSTEM_NAME}\" is not supported in cpuinfo. "
|
"Target operating system \"${CMAKE_SYSTEM_NAME}\" is not supported in cpuinfo. "
|
||||||
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
|
"cpuinfo will compile, but cpuinfo_initialize() will always fail.")
|
||||||
|
@ -74,11 +117,48 @@ ELSEIF(NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN|MSYS|Darwin|Linux|Android
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CPUINFO_SUPPORTED_PLATFORM)
|
||||||
|
IF(CPUINFO_BUILD_MOCK_TESTS OR CPUINFO_BUILD_UNIT_TESTS OR CPUINFO_BUILD_BENCHMARKS)
|
||||||
|
ENABLE_LANGUAGE(CXX)
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
# ---[ Download deps
|
||||||
|
SET(CONFU_DEPENDENCIES_SOURCE_DIR ${CMAKE_SOURCE_DIR}/deps
|
||||||
|
CACHE PATH "Confu-style dependencies source directory")
|
||||||
|
SET(CONFU_DEPENDENCIES_BINARY_DIR ${CMAKE_BINARY_DIR}/deps
|
||||||
|
CACHE PATH "Confu-style dependencies binary directory")
|
||||||
|
|
||||||
|
IF(CPUINFO_SUPPORTED_PLATFORM AND (CPUINFO_BUILD_MOCK_TESTS OR CPUINFO_BUILD_UNIT_TESTS))
|
||||||
|
IF(USE_SYSTEM_GOOGLETEST)
|
||||||
|
FIND_PACKAGE(GTest REQUIRED)
|
||||||
|
ELSEIF(NOT DEFINED GOOGLETEST_SOURCE_DIR)
|
||||||
|
MESSAGE(STATUS "Downloading Google Test to ${CONFU_DEPENDENCIES_SOURCE_DIR}/googletest (define GOOGLETEST_SOURCE_DIR to avoid it)")
|
||||||
|
CONFIGURE_FILE(cmake/DownloadGoogleTest.cmake "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest-download/CMakeLists.txt")
|
||||||
|
EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
|
||||||
|
WORKING_DIRECTORY "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest-download")
|
||||||
|
EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
|
||||||
|
WORKING_DIRECTORY "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest-download")
|
||||||
|
SET(GOOGLETEST_SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googletest" CACHE STRING "Google Test source directory")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CPUINFO_SUPPORTED_PLATFORM AND CPUINFO_BUILD_BENCHMARKS)
|
||||||
|
IF(USE_SYSTEM_GOOGLEBENCHMARK)
|
||||||
|
FIND_PACKAGE(benchmark REQUIRED)
|
||||||
|
ELSEIF(NOT DEFINED GOOGLEBENCHMARK_SOURCE_DIR)
|
||||||
|
MESSAGE(STATUS "Downloading Google Benchmark to ${CONFU_DEPENDENCIES_SOURCE_DIR}/googlebenchmark (define GOOGLEBENCHMARK_SOURCE_DIR to avoid it)")
|
||||||
|
CONFIGURE_FILE(cmake/DownloadGoogleBenchmark.cmake "${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark-download/CMakeLists.txt")
|
||||||
|
EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
|
||||||
|
WORKING_DIRECTORY "${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark-download")
|
||||||
|
EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
|
||||||
|
WORKING_DIRECTORY "${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark-download")
|
||||||
|
SET(GOOGLEBENCHMARK_SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googlebenchmark" CACHE STRING "Google Benchmark source directory")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
# ---[ cpuinfo library
|
# ---[ cpuinfo library
|
||||||
SET(CPUINFO_SRCS
|
SET(CPUINFO_SRCS src/api.c src/cache.c src/init.c src/log.c)
|
||||||
src/init.c
|
|
||||||
src/api.c
|
|
||||||
src/cache.c)
|
|
||||||
|
|
||||||
IF(CPUINFO_SUPPORTED_PLATFORM)
|
IF(CPUINFO_SUPPORTED_PLATFORM)
|
||||||
IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND (CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$" OR IOS_ARCH MATCHES "^(i386|x86_64)$"))
|
IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND (CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$" OR IOS_ARCH MATCHES "^(i386|x86_64)$"))
|
||||||
|
@ -97,12 +177,18 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
|
||||||
LIST(APPEND CPUINFO_SRCS
|
LIST(APPEND CPUINFO_SRCS
|
||||||
src/x86/linux/init.c
|
src/x86/linux/init.c
|
||||||
src/x86/linux/cpuinfo.c)
|
src/x86/linux/cpuinfo.c)
|
||||||
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
ELSEIF(IS_APPLE_OS)
|
||||||
LIST(APPEND CPUINFO_SRCS src/x86/mach/init.c)
|
LIST(APPEND CPUINFO_SRCS src/x86/mach/init.c)
|
||||||
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN|MSYS)$")
|
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "^(Windows|WindowsStore|CYGWIN|MSYS)$")
|
||||||
LIST(APPEND CPUINFO_SRCS src/x86/windows/init.c)
|
LIST(APPEND CPUINFO_SRCS src/x86/windows/init.c)
|
||||||
|
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||||
|
LIST(APPEND CPUINFO_SRCS src/x86/freebsd/init.c)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ELSEIF(CPUINFO_TARGET_PROCESSOR MATCHES "^(armv[5-8].*|aarch64|arm64)$" OR IOS_ARCH MATCHES "^(armv7.*|arm64.*)$")
|
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "^Windows" AND CPUINFO_TARGET_PROCESSOR MATCHES "^(ARM64|arm64)$")
|
||||||
|
LIST(APPEND CPUINFO_SRCS
|
||||||
|
src/arm/windows/init-by-logical-sys-info.c
|
||||||
|
src/arm/windows/init.c)
|
||||||
|
ELSEIF(CPUINFO_TARGET_PROCESSOR MATCHES "^(armv[5-8].*|aarch64|arm64.*)$" OR IOS_ARCH MATCHES "^(armv7.*|arm64.*)$")
|
||||||
LIST(APPEND CPUINFO_SRCS
|
LIST(APPEND CPUINFO_SRCS
|
||||||
src/arm/uarch.c
|
src/arm/uarch.c
|
||||||
src/arm/cache.c)
|
src/arm/cache.c)
|
||||||
|
@ -122,13 +208,22 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
|
||||||
ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)$")
|
ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)$")
|
||||||
LIST(APPEND CPUINFO_SRCS src/arm/linux/aarch64-isa.c)
|
LIST(APPEND CPUINFO_SRCS src/arm/linux/aarch64-isa.c)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ELSEIF(IOS OR (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CPUINFO_TARGET_PROCESSOR STREQUAL "arm64"))
|
ELSEIF(IS_APPLE_OS AND CPUINFO_TARGET_PROCESSOR MATCHES "arm64.*")
|
||||||
LIST(APPEND CPUINFO_SRCS src/arm/mach/init.c)
|
LIST(APPEND CPUINFO_SRCS src/arm/mach/init.c)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
IF(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||||
LIST(APPEND CPUINFO_SRCS
|
LIST(APPEND CPUINFO_SRCS
|
||||||
src/arm/android/properties.c)
|
src/arm/android/properties.c)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
ELSEIF(CPUINFO_TARGET_PROCESSOR MATCHES "^(riscv(32|64))$")
|
||||||
|
LIST(APPEND CPUINFO_SRCS
|
||||||
|
src/riscv/uarch.c)
|
||||||
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
LIST(APPEND CPUINFO_SRCS
|
||||||
|
src/riscv/linux/init.c
|
||||||
|
src/riscv/linux/riscv-hw.c
|
||||||
|
src/riscv/linux/riscv-isa.c)
|
||||||
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
||||||
|
@ -142,11 +237,13 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
|
||||||
src/linux/multiline.c
|
src/linux/multiline.c
|
||||||
src/linux/cpulist.c
|
src/linux/cpulist.c
|
||||||
src/linux/processors.c)
|
src/linux/processors.c)
|
||||||
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
ELSEIF(IS_APPLE_OS)
|
||||||
LIST(APPEND CPUINFO_SRCS src/mach/topology.c)
|
LIST(APPEND CPUINFO_SRCS src/mach/topology.c)
|
||||||
|
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||||
|
LIST(APPEND CPUINFO_SRCS src/freebsd/topology.c)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||||
SET(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
SET(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||||
SET(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
SET(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||||
FIND_PACKAGE(Threads REQUIRED)
|
FIND_PACKAGE(Threads REQUIRED)
|
||||||
|
@ -166,34 +263,43 @@ ADD_LIBRARY(cpuinfo_internals STATIC ${CPUINFO_SRCS})
|
||||||
CPUINFO_TARGET_ENABLE_C99(cpuinfo)
|
CPUINFO_TARGET_ENABLE_C99(cpuinfo)
|
||||||
CPUINFO_TARGET_ENABLE_C99(cpuinfo_internals)
|
CPUINFO_TARGET_ENABLE_C99(cpuinfo_internals)
|
||||||
CPUINFO_TARGET_RUNTIME_LIBRARY(cpuinfo)
|
CPUINFO_TARGET_RUNTIME_LIBRARY(cpuinfo)
|
||||||
IF(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN|MSYS)$")
|
IF(CMAKE_SYSTEM_NAME MATCHES "^(Windows|WindowsStore|CYGWIN|MSYS)$")
|
||||||
# Target Windows 7+ API
|
# Target Windows 7+ API
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE _WIN32_WINNT=0x0601)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE _WIN32_WINNT=0x0601 _CRT_SECURE_NO_WARNINGS)
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo_internals PRIVATE _WIN32_WINNT=0x0601)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo_internals PRIVATE _WIN32_WINNT=0x0601 _CRT_SECURE_NO_WARNINGS)
|
||||||
|
# Explicitly link Kernel32 for UWP build
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||||
|
TARGET_LINK_LIBRARIES(cpuinfo PUBLIC Kernel32)
|
||||||
|
endif()
|
||||||
|
ENDIF()
|
||||||
|
IF(ANDROID AND NOT CPUINFO_LOG_TO_STDIO)
|
||||||
|
TARGET_LINK_LIBRARIES(cpuinfo PRIVATE "log")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
SET_TARGET_PROPERTIES(cpuinfo PROPERTIES PUBLIC_HEADER include/cpuinfo.h)
|
SET_TARGET_PROPERTIES(cpuinfo PROPERTIES PUBLIC_HEADER include/cpuinfo.h)
|
||||||
TARGET_INCLUDE_DIRECTORIES(cpuinfo BEFORE PUBLIC include)
|
TARGET_INCLUDE_DIRECTORIES(cpuinfo BEFORE PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
TARGET_INCLUDE_DIRECTORIES(cpuinfo BEFORE PRIVATE src)
|
TARGET_INCLUDE_DIRECTORIES(cpuinfo BEFORE PRIVATE src)
|
||||||
TARGET_INCLUDE_DIRECTORIES(cpuinfo_internals BEFORE PUBLIC include src)
|
TARGET_INCLUDE_DIRECTORIES(cpuinfo_internals BEFORE PUBLIC include src)
|
||||||
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE "CPUINFO_LOG_TO_STDIO=$<BOOL:${CPUINFO_LOG_TO_STDIO}>")
|
||||||
IF(CPUINFO_LOG_LEVEL STREQUAL "default")
|
IF(CPUINFO_LOG_LEVEL STREQUAL "default")
|
||||||
# default logging level: error (subject to change)
|
# default logging level: error (subject to change)
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=2)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE "CPUINFO_LOG_LEVEL=2")
|
||||||
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "debug")
|
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "debug")
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=5)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE "CPUINFO_LOG_LEVEL=5")
|
||||||
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "info")
|
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "info")
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=4)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE "CPUINFO_LOG_LEVEL=4")
|
||||||
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "warning")
|
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "warning")
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=3)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE "CPUINFO_LOG_LEVEL=3")
|
||||||
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "error")
|
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "error")
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=2)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE "CPUINFO_LOG_LEVEL=2")
|
||||||
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "fatal")
|
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "fatal")
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=1)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE "CPUINFO_LOG_LEVEL=1")
|
||||||
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "none")
|
ELSEIF(CPUINFO_LOG_LEVEL STREQUAL "none")
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE CPUINFO_LOG_LEVEL=0)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE "CPUINFO_LOG_LEVEL=0")
|
||||||
ELSE()
|
ELSE()
|
||||||
MESSAGE(FATAL_ERROR "Unsupported logging level ${CPUINFO_LOG_LEVEL}")
|
MESSAGE(FATAL_ERROR "Unsupported logging level ${CPUINFO_LOG_LEVEL}")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo_internals PRIVATE CPUINFO_LOG_LEVEL=0)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo_internals PRIVATE "CPUINFO_LOG_LEVEL=0")
|
||||||
|
TARGET_COMPILE_DEFINITIONS(cpuinfo_internals PRIVATE "CPUINFO_LOG_TO_STDIO=1")
|
||||||
|
|
||||||
IF(CPUINFO_SUPPORTED_PLATFORM)
|
IF(CPUINFO_SUPPORTED_PLATFORM)
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo INTERFACE CPUINFO_SUPPORTED_PLATFORM=1)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo INTERFACE CPUINFO_SUPPORTED_PLATFORM=1)
|
||||||
|
@ -202,22 +308,618 @@ IF(CPUINFO_SUPPORTED_PLATFORM)
|
||||||
TARGET_LINK_LIBRARIES(cpuinfo_internals PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
TARGET_LINK_LIBRARIES(cpuinfo_internals PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE _GNU_SOURCE=1)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo PRIVATE _GNU_SOURCE=1)
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo_internals PRIVATE _GNU_SOURCE=1)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo_internals PRIVATE _GNU_SOURCE=1)
|
||||||
|
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||||
|
TARGET_LINK_LIBRARIES(cpuinfo PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
TARGET_LINK_LIBRARIES(cpuinfo_internals PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ELSE()
|
ELSE()
|
||||||
TARGET_COMPILE_DEFINITIONS(cpuinfo INTERFACE CPUINFO_SUPPORTED_PLATFORM=0)
|
TARGET_COMPILE_DEFINITIONS(cpuinfo INTERFACE CPUINFO_SUPPORTED_PLATFORM=0)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
# ---[ cpuinfo dependencies: clog
|
ADD_LIBRARY(${PROJECT_NAME}::cpuinfo ALIAS cpuinfo)
|
||||||
IF(NOT DEFINED CLOG_SOURCE_DIR)
|
|
||||||
SET(CLOG_SOURCE_DIR "${PROJECT_SOURCE_DIR}/deps/clog")
|
# support find_package(cpuinfo CONFIG)
|
||||||
|
INCLUDE(CMakePackageConfigHelpers)
|
||||||
|
GET_FILENAME_COMPONENT(CONFIG_FILE_PATH ${CMAKE_CURRENT_BINARY_DIR}/cpuinfo-config.cmake ABSOLUTE)
|
||||||
|
CONFIGURE_PACKAGE_CONFIG_FILE(
|
||||||
|
cmake/cpuinfo-config.cmake.in ${CONFIG_FILE_PATH}
|
||||||
|
INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME})
|
||||||
|
INSTALL(FILES ${CONFIG_FILE_PATH}
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}) # cpuinfo_DIR ${prefix}/share/cpuinfo
|
||||||
|
|
||||||
|
INSTALL(TARGETS cpuinfo
|
||||||
|
EXPORT cpuinfo-targets
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
|
||||||
|
INSTALL(EXPORT cpuinfo-targets
|
||||||
|
NAMESPACE ${PROJECT_NAME}:: # IMPORTED cpuinfo::cpuinfo
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME})
|
||||||
|
|
||||||
|
# ---[ cpuinfo micro-benchmarks
|
||||||
|
IF(CPUINFO_SUPPORTED_PLATFORM AND CPUINFO_BUILD_BENCHMARKS)
|
||||||
|
# ---[ Build google benchmark
|
||||||
|
IF(NOT TARGET benchmark AND NOT USE_SYSTEM_GOOGLEBENCHMARK)
|
||||||
|
SET(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "")
|
||||||
|
ADD_SUBDIRECTORY(
|
||||||
|
"${GOOGLEBENCHMARK_SOURCE_DIR}"
|
||||||
|
"${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CMAKE_SYSTEM_NAME MATCHES "^(Linux|Android)$")
|
||||||
|
ADD_EXECUTABLE(get-current-bench bench/get-current.cc)
|
||||||
|
TARGET_LINK_LIBRARIES(get-current-bench cpuinfo benchmark)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(init-bench bench/init.cc)
|
||||||
|
TARGET_LINK_LIBRARIES(init-bench cpuinfo benchmark)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
IF(NOT TARGET clog)
|
|
||||||
SET(CLOG_BUILD_TESTS OFF CACHE BOOL "")
|
IF(CPUINFO_SUPPORTED_PLATFORM)
|
||||||
SET(CLOG_RUNTIME_TYPE "${CPUINFO_RUNTIME_TYPE}" CACHE STRING "")
|
IF(CPUINFO_BUILD_MOCK_TESTS OR CPUINFO_BUILD_UNIT_TESTS)
|
||||||
ADD_SUBDIRECTORY(
|
# ---[ Build google test
|
||||||
"${CLOG_SOURCE_DIR}")
|
IF(NOT TARGET gtest AND NOT USE_SYSTEM_GOOGLETEST)
|
||||||
# We build static version of clog but a dynamic library may indirectly depend on it
|
IF(MSVC AND NOT CPUINFO_RUNTIME_TYPE STREQUAL "static")
|
||||||
SET_PROPERTY(TARGET clog PROPERTY POSITION_INDEPENDENT_CODE ON)
|
SET(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
ENDIF()
|
||||||
|
ADD_SUBDIRECTORY(
|
||||||
|
"${GOOGLETEST_SOURCE_DIR}"
|
||||||
|
"${CONFU_DEPENDENCIES_BINARY_DIR}/googletest")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
# ---[ cpuinfo mock library and mock tests
|
||||||
|
IF(CPUINFO_SUPPORTED_PLATFORM AND CPUINFO_BUILD_MOCK_TESTS)
|
||||||
|
SET(CPUINFO_MOCK_SRCS "${CPUINFO_SRCS}")
|
||||||
|
IF(CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$")
|
||||||
|
LIST(APPEND CPUINFO_MOCK_SRCS src/x86/mockcpuid.c)
|
||||||
|
ENDIF()
|
||||||
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||||
|
LIST(APPEND CPUINFO_MOCK_SRCS src/linux/mockfile.c)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
ADD_LIBRARY(cpuinfo_mock STATIC ${CPUINFO_MOCK_SRCS})
|
||||||
|
CPUINFO_TARGET_ENABLE_C99(cpuinfo_mock)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(cpuinfo_mock)
|
||||||
|
SET_TARGET_PROPERTIES(cpuinfo_mock PROPERTIES PUBLIC_HEADER include/cpuinfo.h)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(cpuinfo_mock BEFORE PUBLIC include)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(cpuinfo_mock BEFORE PRIVATE src)
|
||||||
|
TARGET_COMPILE_DEFINITIONS(cpuinfo_mock PUBLIC "CPUINFO_MOCK=1")
|
||||||
|
TARGET_COMPILE_DEFINITIONS(cpuinfo_mock PRIVATE "CPUINFO_LOG_LEVEL=5")
|
||||||
|
TARGET_COMPILE_DEFINITIONS(cpuinfo_mock PRIVATE "CPUINFO_LOG_TO_STDIO=1")
|
||||||
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||||
|
TARGET_LINK_LIBRARIES(cpuinfo_mock PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
TARGET_COMPILE_DEFINITIONS(cpuinfo_mock PRIVATE _GNU_SOURCE=1)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Android" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv5te|armv7-a)$")
|
||||||
|
ADD_EXECUTABLE(atm7029b-tablet-test test/mock/atm7029b-tablet.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(atm7029b-tablet-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(atm7029b-tablet-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME atm7029b-tablet-test COMMAND atm7029b-tablet-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(blu-r1-hd-test test/mock/blu-r1-hd.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(blu-r1-hd-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(blu-r1-hd-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME blu-r1-hd-test COMMAND blu-r1-hd-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-a3-2016-eu-test test/mock/galaxy-a3-2016-eu.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-a3-2016-eu-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-a3-2016-eu-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-a3-2016-eu-test COMMAND galaxy-a3-2016-eu-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-a8-2016-duos-test test/mock/galaxy-a8-2016-duos.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-a8-2016-duos-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-a8-2016-duos-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-a8-2016-duos-test COMMAND galaxy-a8-2016-duos-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-grand-prime-value-edition-test test/mock/galaxy-grand-prime-value-edition.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-grand-prime-value-edition-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-grand-prime-value-edition-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-grand-prime-value-edition-test COMMAND galaxy-grand-prime-value-edition-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-j1-2016-test test/mock/galaxy-j1-2016.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-j1-2016-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-j1-2016-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-j1-2016-test COMMAND galaxy-j1-2016-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-j5-test test/mock/galaxy-j5.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-j5-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-j5-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-j5-test COMMAND galaxy-j5-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-j7-prime-test test/mock/galaxy-j7-prime.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-j7-prime-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-j7-prime-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-j7-prime-test COMMAND galaxy-j7-prime-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-j7-tmobile-test test/mock/galaxy-j7-tmobile.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-j7-tmobile-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-j7-tmobile-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-j7-tmobile-test COMMAND galaxy-j7-tmobile-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-j7-uae-test test/mock/galaxy-j7-uae.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-j7-uae-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-j7-uae-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-j7-uae-test COMMAND galaxy-j7-uae-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s3-us-test test/mock/galaxy-s3-us.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s3-us-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s3-us-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s3-us-test COMMAND galaxy-s3-us-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s4-us-test test/mock/galaxy-s4-us.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s4-us-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s4-us-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s4-us-test COMMAND galaxy-s4-us-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s5-global-test test/mock/galaxy-s5-global.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s5-global-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s5-global-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s5-global-test COMMAND galaxy-s5-global-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s5-us-test test/mock/galaxy-s5-us.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s5-us-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s5-us-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s5-us-test COMMAND galaxy-s5-us-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-tab-3-7.0-test test/mock/galaxy-tab-3-7.0.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-tab-3-7.0-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-tab-3-7.0-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-tab-3-7.0-test COMMAND galaxy-tab-3-7.0-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-tab-3-lite-test test/mock/galaxy-tab-3-lite.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-tab-3-lite-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-tab-3-lite-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-tab-3-lite-test COMMAND galaxy-tab-3-lite-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-win-duos-test test/mock/galaxy-win-duos.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-win-duos-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-win-duos-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-win-duos-test COMMAND galaxy-win-duos-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-ascend-p7-test test/mock/huawei-ascend-p7.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-ascend-p7-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-ascend-p7-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-ascend-p7-test COMMAND huawei-ascend-p7-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-honor-6-test test/mock/huawei-honor-6.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-honor-6-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-honor-6-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-honor-6-test COMMAND huawei-honor-6-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(lenovo-a6600-plus-test test/mock/lenovo-a6600-plus.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(lenovo-a6600-plus-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(lenovo-a6600-plus-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME lenovo-a6600-plus-test COMMAND lenovo-a6600-plus-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(lenovo-vibe-x2-test test/mock/lenovo-vibe-x2.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(lenovo-vibe-x2-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(lenovo-vibe-x2-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME lenovo-vibe-x2-test COMMAND lenovo-vibe-x2-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(lg-k10-eu-test test/mock/lg-k10-eu.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(lg-k10-eu-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(lg-k10-eu-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME lg-k10-eu-test COMMAND lg-k10-eu-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(lg-optimus-g-pro-test test/mock/lg-optimus-g-pro.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(lg-optimus-g-pro-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(lg-optimus-g-pro-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME lg-optimus-g-pro-test COMMAND lg-optimus-g-pro-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(moto-e-gen1-test test/mock/moto-e-gen1.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(moto-e-gen1-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(moto-e-gen1-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME moto-e-gen1-test COMMAND moto-e-gen1-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(moto-g-gen1-test test/mock/moto-g-gen1.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(moto-g-gen1-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(moto-g-gen1-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME moto-g-gen1-test COMMAND moto-g-gen1-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(moto-g-gen2-test test/mock/moto-g-gen2.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(moto-g-gen2-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(moto-g-gen2-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME moto-g-gen2-test COMMAND moto-g-gen2-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(moto-g-gen3-test test/mock/moto-g-gen3.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(moto-g-gen3-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(moto-g-gen3-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME moto-g-gen3-test COMMAND moto-g-gen3-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(moto-g-gen4-test test/mock/moto-g-gen4.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(moto-g-gen4-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(moto-g-gen4-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME moto-g-gen4-test COMMAND moto-g-gen4-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(moto-g-gen5-test test/mock/moto-g-gen5.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(moto-g-gen5-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(moto-g-gen5-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME moto-g-gen5-test COMMAND moto-g-gen5-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(nexus-s-test test/mock/nexus-s.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(nexus-s-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(nexus-s-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME nexus-s-test COMMAND nexus-s-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(nexus4-test test/mock/nexus4.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(nexus4-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(nexus4-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME nexus4-test COMMAND nexus4-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(nexus6-test test/mock/nexus6.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(nexus6-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(nexus6-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME nexus6-test COMMAND nexus6-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(nexus10-test test/mock/nexus10.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(nexus10-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(nexus10-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME nexus10-test COMMAND nexus10-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(padcod-10.1-test test/mock/padcod-10.1.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(padcod-10.1-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(padcod-10.1-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME padcod-10.1-test COMMAND padcod-10.1-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(xiaomi-redmi-2a-test test/mock/xiaomi-redmi-2a.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(xiaomi-redmi-2a-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(xiaomi-redmi-2a-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME xiaomi-redmi-2a-test COMMAND xiaomi-redmi-2a-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(xperia-sl-test test/mock/xperia-sl.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(xperia-sl-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(xperia-sl-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME xperia-sl-test COMMAND xperia-sl-test)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Android" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv5te|armv7-a|aarch64)$")
|
||||||
|
ADD_EXECUTABLE(alcatel-revvl-test test/mock/alcatel-revvl.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(alcatel-revvl-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(alcatel-revvl-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME alcatel-revvl-test COMMAND alcatel-revvl-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-a8-2018-test test/mock/galaxy-a8-2018.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-a8-2018-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-a8-2018-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-a8-2018-test COMMAND galaxy-a8-2018-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-c9-pro-test test/mock/galaxy-c9-pro.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-c9-pro-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-c9-pro-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-c9-pro-test COMMAND galaxy-c9-pro-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s6-test test/mock/galaxy-s6.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s6-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s6-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s6-test COMMAND galaxy-s6-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s7-us-test test/mock/galaxy-s7-us.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s7-us-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s7-us-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s7-us-test COMMAND galaxy-s7-us-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s7-global-test test/mock/galaxy-s7-global.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s7-global-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s7-global-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s7-global-test COMMAND galaxy-s7-global-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s8-us-test test/mock/galaxy-s8-us.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s8-us-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s8-us-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s8-us-test COMMAND galaxy-s8-us-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s8-global-test test/mock/galaxy-s8-global.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s8-global-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s8-global-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s8-global-test COMMAND galaxy-s8-global-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s9-us-test test/mock/galaxy-s9-us.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s9-us-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s9-us-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s9-us-test COMMAND galaxy-s9-us-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(galaxy-s9-global-test test/mock/galaxy-s9-global.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(galaxy-s9-global-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(galaxy-s9-global-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME galaxy-s9-global-test COMMAND galaxy-s9-global-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-mate-8-test test/mock/huawei-mate-8.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-mate-8-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-mate-8-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-mate-8-test COMMAND huawei-mate-8-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-mate-9-test test/mock/huawei-mate-9.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-mate-9-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-mate-9-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-mate-9-test COMMAND huawei-mate-9-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-mate-10-test test/mock/huawei-mate-10.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-mate-10-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-mate-10-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-mate-10-test COMMAND huawei-mate-10-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-mate-20-test test/mock/huawei-mate-20.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-mate-20-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-mate-20-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-mate-20-test COMMAND huawei-mate-20-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-p8-lite-test test/mock/huawei-p8-lite.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-p8-lite-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-p8-lite-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-p8-lite-test COMMAND huawei-p8-lite-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-p9-lite-test test/mock/huawei-p9-lite.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-p9-lite-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-p9-lite-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-p9-lite-test COMMAND huawei-p9-lite-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(huawei-p20-pro-test test/mock/huawei-p20-pro.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(huawei-p20-pro-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(huawei-p20-pro-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME huawei-p20-pro-test COMMAND huawei-p20-pro-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(iconia-one-10-test test/mock/iconia-one-10.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(iconia-one-10-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(iconia-one-10-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME iconia-one-10-test COMMAND iconia-one-10-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(meizu-pro-6-test test/mock/meizu-pro-6.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(meizu-pro-6-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(meizu-pro-6-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME meizu-pro-6-test COMMAND meizu-pro-6-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(meizu-pro-6s-test test/mock/meizu-pro-6s.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(meizu-pro-6s-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(meizu-pro-6s-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME meizu-pro-6s-test COMMAND meizu-pro-6s-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(meizu-pro-7-plus-test test/mock/meizu-pro-7-plus.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(meizu-pro-7-plus-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(meizu-pro-7-plus-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME meizu-pro-7-plus-test COMMAND meizu-pro-7-plus-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(nexus5x-test test/mock/nexus5x.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(nexus5x-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(nexus5x-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME nexus5x-test COMMAND nexus5x-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(nexus6p-test test/mock/nexus6p.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(nexus6p-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(nexus6p-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME nexus6p-test COMMAND nexus6p-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(nexus9-test test/mock/nexus9.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(nexus9-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(nexus9-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME nexus9-test COMMAND nexus9-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(oneplus-3t-test test/mock/oneplus-3t.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(oneplus-3t-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(oneplus-3t-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME oneplus-3t-test COMMAND oneplus-3t-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(oneplus-5-test test/mock/oneplus-5.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(oneplus-5-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(oneplus-5-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME oneplus-5-test COMMAND oneplus-5-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(oneplus-5t-test test/mock/oneplus-5t.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(oneplus-5t-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(oneplus-5t-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME oneplus-5t-test COMMAND oneplus-5t-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(oppo-a37-test test/mock/oppo-a37.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(oppo-a37-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(oppo-a37-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME oppo-a37-test COMMAND oppo-a37-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(oppo-r9-test test/mock/oppo-r9.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(oppo-r9-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(oppo-r9-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME oppo-r9-test COMMAND oppo-r9-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(oppo-r15-test test/mock/oppo-r15.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(oppo-r15-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(oppo-r15-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME oppo-r15-test COMMAND oppo-r15-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(pixel-test test/mock/pixel.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(pixel-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(pixel-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME pixel-test COMMAND pixel-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(pixel-c-test test/mock/pixel-c.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(pixel-c-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(pixel-c-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME pixel-c-test COMMAND pixel-c-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(pixel-xl-test test/mock/pixel-xl.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(pixel-xl-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(pixel-xl-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME pixel-xl-test COMMAND pixel-xl-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(pixel-2-xl-test test/mock/pixel-2-xl.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(pixel-2-xl-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(pixel-2-xl-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME pixel-2-xl-test COMMAND pixel-2-xl-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(xiaomi-mi-5c-test test/mock/xiaomi-mi-5c.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(xiaomi-mi-5c-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(xiaomi-mi-5c-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME xiaomi-mi-5c-test COMMAND xiaomi-mi-5c-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(xiaomi-redmi-note-3-test test/mock/xiaomi-redmi-note-3.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(xiaomi-redmi-note-3-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(xiaomi-redmi-note-3-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME xiaomi-redmi-note-3-test COMMAND xiaomi-redmi-note-3-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(xiaomi-redmi-note-4-test test/mock/xiaomi-redmi-note-4.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(xiaomi-redmi-note-4-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(xiaomi-redmi-note-4-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME xiaomi-redmi-note-4-test COMMAND xiaomi-redmi-note-4-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(xperia-c4-dual-test test/mock/xperia-c4-dual.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(xperia-c4-dual-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(xperia-c4-dual-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME xperia-c4-dual-test COMMAND xperia-c4-dual-test)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Android" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(i686|x86_64)$")
|
||||||
|
ADD_EXECUTABLE(alldocube-iwork8-test test/mock/alldocube-iwork8.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(alldocube-iwork8-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(alldocube-iwork8-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME alldocube-iwork8-test COMMAND alldocube-iwork8-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(leagoo-t5c-test test/mock/leagoo-t5c.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(leagoo-t5c-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(leagoo-t5c-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME leagoo-t5c-test COMMAND leagoo-t5c-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(memo-pad-7-test test/mock/memo-pad-7.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(memo-pad-7-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(memo-pad-7-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME memo-pad-7-test COMMAND memo-pad-7-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(zenfone-c-test test/mock/zenfone-c.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(zenfone-c-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(zenfone-c-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME zenfone-c-test COMMAND zenfone-c-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(zenfone-2-test test/mock/zenfone-2.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(zenfone-2-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(zenfone-2-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME zenfone-2-test COMMAND zenfone-2-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(zenfone-2e-test test/mock/zenfone-2e.cc)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(zenfone-2e-test BEFORE PRIVATE test/mock)
|
||||||
|
TARGET_LINK_LIBRARIES(zenfone-2e-test PRIVATE cpuinfo_mock gtest)
|
||||||
|
ADD_TEST(NAME zenfone-2e-test COMMAND zenfone-2e-test)
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
# ---[ cpuinfo unit tests
|
||||||
|
IF(CPUINFO_SUPPORTED_PLATFORM AND CPUINFO_BUILD_UNIT_TESTS)
|
||||||
|
ADD_EXECUTABLE(init-test test/init.cc)
|
||||||
|
CPUINFO_TARGET_ENABLE_CXX11(init-test)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(init-test)
|
||||||
|
TARGET_LINK_LIBRARIES(init-test PRIVATE cpuinfo gtest gtest_main)
|
||||||
|
ADD_TEST(NAME init-test COMMAND init-test)
|
||||||
|
|
||||||
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||||
|
ADD_EXECUTABLE(get-current-test test/get-current.cc)
|
||||||
|
CPUINFO_TARGET_ENABLE_CXX11(get-current-test)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(get-current-test)
|
||||||
|
TARGET_LINK_LIBRARIES(get-current-test PRIVATE cpuinfo gtest gtest_main)
|
||||||
|
ADD_TEST(NAME get-current-test COMMAND get-current-test)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$")
|
||||||
|
ADD_EXECUTABLE(brand-string-test test/name/brand-string.cc)
|
||||||
|
CPUINFO_TARGET_ENABLE_CXX11(brand-string-test)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(brand-string-test)
|
||||||
|
TARGET_LINK_LIBRARIES(brand-string-test PRIVATE cpuinfo_internals gtest gtest_main)
|
||||||
|
ADD_TEST(NAME brand-string-test COMMAND brand-string-test)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CMAKE_SYSTEM_NAME STREQUAL "Android" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv[5-8].*|aarch64)$")
|
||||||
|
ADD_LIBRARY(android_properties_interface STATIC test/name/android-properties-interface.c)
|
||||||
|
CPUINFO_TARGET_ENABLE_C99(android_properties_interface)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(android_properties_interface)
|
||||||
|
TARGET_LINK_LIBRARIES(android_properties_interface PRIVATE cpuinfo_internals)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(chipset-test
|
||||||
|
test/name/proc-cpuinfo-hardware.cc
|
||||||
|
test/name/ro-product-board.cc
|
||||||
|
test/name/ro-board-platform.cc
|
||||||
|
test/name/ro-mediatek-platform.cc
|
||||||
|
test/name/ro-arch.cc
|
||||||
|
test/name/ro-chipname.cc
|
||||||
|
test/name/android-properties.cc)
|
||||||
|
CPUINFO_TARGET_ENABLE_CXX11(chipset-test)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(chipset-test)
|
||||||
|
TARGET_LINK_LIBRARIES(chipset-test PRIVATE android_properties_interface gtest gtest_main)
|
||||||
|
ADD_TEST(NAME chipset-test COMMAND chipset-test)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(cache-test test/arm-cache.cc)
|
||||||
|
CPUINFO_TARGET_ENABLE_CXX11(cache-test)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(cache-test)
|
||||||
|
TARGET_COMPILE_DEFINITIONS(cache-test PRIVATE __STDC_LIMIT_MACROS=1 __STDC_CONSTANT_MACROS=1)
|
||||||
|
TARGET_LINK_LIBRARIES(cache-test PRIVATE cpuinfo_internals gtest gtest_main)
|
||||||
|
ADD_TEST(NAME cache-test COMMAND cache-test)
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
# ---[ Helper and debug tools
|
||||||
|
IF(CPUINFO_SUPPORTED_PLATFORM AND CPUINFO_BUILD_TOOLS)
|
||||||
|
ADD_EXECUTABLE(isa-info tools/isa-info.c)
|
||||||
|
CPUINFO_TARGET_ENABLE_C99(isa-info)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(isa-info)
|
||||||
|
TARGET_LINK_LIBRARIES(isa-info PRIVATE cpuinfo)
|
||||||
|
INSTALL(TARGETS isa-info RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(cpu-info tools/cpu-info.c)
|
||||||
|
CPUINFO_TARGET_ENABLE_C99(cpu-info)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(cpu-info)
|
||||||
|
TARGET_LINK_LIBRARIES(cpu-info PRIVATE cpuinfo)
|
||||||
|
INSTALL(TARGETS cpu-info RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(cache-info tools/cache-info.c)
|
||||||
|
CPUINFO_TARGET_ENABLE_C99(cache-info)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(cache-info)
|
||||||
|
TARGET_LINK_LIBRARIES(cache-info PRIVATE cpuinfo)
|
||||||
|
INSTALL(TARGETS cache-info RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
|
IF(CMAKE_SYSTEM_NAME MATCHES "^(Android|Linux)$" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv[5-8].*|aarch64)$")
|
||||||
|
ADD_EXECUTABLE(auxv-dump tools/auxv-dump.c)
|
||||||
|
CPUINFO_TARGET_ENABLE_C99(auxv-dump)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(auxv-dump)
|
||||||
|
TARGET_LINK_LIBRARIES(auxv-dump PRIVATE ${CMAKE_DL_LIBS} cpuinfo)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(cpuinfo-dump tools/cpuinfo-dump.c)
|
||||||
|
CPUINFO_TARGET_ENABLE_C99(cpuinfo-dump)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(cpuinfo-dump)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(CPUINFO_TARGET_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$")
|
||||||
|
ADD_EXECUTABLE(cpuid-dump tools/cpuid-dump.c)
|
||||||
|
CPUINFO_TARGET_ENABLE_C99(cpuid-dump)
|
||||||
|
CPUINFO_TARGET_RUNTIME_LIBRARY(cpuid-dump)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(cpuid-dump BEFORE PRIVATE src)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(cpuid-dump BEFORE PRIVATE include)
|
||||||
|
INSTALL(TARGETS cpuid-dump RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
# ---[ pkg-config manifest. This is mostly from JsonCpp...
|
||||||
|
IF(CPUINFO_BUILD_PKG_CONFIG)
|
||||||
|
|
||||||
|
FUNCTION(JOIN_PATHS joined_path first_path_segment)
|
||||||
|
SET(temp_path "${first_path_segment}")
|
||||||
|
FOREACH(current_segment IN LISTS ARGN)
|
||||||
|
IF(NOT ("${current_segment}" STREQUAL ""))
|
||||||
|
IF(IS_ABSOLUTE "${current_segment}")
|
||||||
|
SET(temp_path "${current_segment}")
|
||||||
|
ELSE()
|
||||||
|
SET(temp_path "${temp_path}/${current_segment}")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
ENDFOREACH()
|
||||||
|
SET(${joined_path} "${temp_path}" PARENT_SCOPE)
|
||||||
|
ENDFUNCTION()
|
||||||
|
|
||||||
|
JOIN_PATHS(libdir_for_pc_file "\${exec_prefix}" "${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
JOIN_PATHS(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
|
|
||||||
|
CONFIGURE_FILE(
|
||||||
|
"libcpuinfo.pc.in"
|
||||||
|
"libcpuinfo.pc"
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/libcpuinfo.pc"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||||
|
|
||||||
ENDIF()
|
ENDIF()
|
||||||
TARGET_LINK_LIBRARIES(cpuinfo PRIVATE clog)
|
|
||||||
TARGET_LINK_LIBRARIES(cpuinfo_internals PRIVATE clog)
|
|
|
@ -48,7 +48,7 @@ Detect if target is a 32-bit or 64-bit ARM system:
|
||||||
#endif
|
#endif
|
||||||
```
|
```
|
||||||
|
|
||||||
Check if the host CPU support ARM NEON
|
Check if the host CPU supports ARM NEON
|
||||||
|
|
||||||
```c
|
```c
|
||||||
cpuinfo_initialize();
|
cpuinfo_initialize();
|
||||||
|
@ -151,6 +151,36 @@ executable(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Bazel
|
||||||
|
|
||||||
|
This project can be built using [Bazel](https://bazel.build/install).
|
||||||
|
|
||||||
|
You can also use this library as a dependency to your Bazel project. Add to the `WORKSPACE` file:
|
||||||
|
|
||||||
|
```python
|
||||||
|
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||||
|
|
||||||
|
git_repository(
|
||||||
|
name = "org_pytorch_cpuinfo",
|
||||||
|
branch = "master",
|
||||||
|
remote = "https://github.com/Vertexwahn/cpuinfo.git",
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
And to your `BUILD` file:
|
||||||
|
|
||||||
|
```python
|
||||||
|
cc_binary(
|
||||||
|
name = "cpuinfo_test",
|
||||||
|
srcs = [
|
||||||
|
# ...
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"@org_pytorch_cpuinfo//:cpuinfo",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
### CMake
|
### CMake
|
||||||
|
|
||||||
To use with CMake use the [FindPkgConfig](https://cmake.org/cmake/help/latest/module/FindPkgConfig.html) module. Here is an example:
|
To use with CMake use the [FindPkgConfig](https://cmake.org/cmake/help/latest/module/FindPkgConfig.html) module. Here is an example:
|
||||||
|
@ -220,12 +250,14 @@ LDFLAGS+= $(pkg-config --libs libcpuinfo)
|
||||||
- [x] x86-64 (iPhone simulator)
|
- [x] x86-64 (iPhone simulator)
|
||||||
- [x] ARMv7
|
- [x] ARMv7
|
||||||
- [x] ARM64
|
- [x] ARM64
|
||||||
- [x] OS X
|
- [x] macOS
|
||||||
- [x] x86
|
- [x] x86
|
||||||
- [x] x86-64
|
- [x] x86-64
|
||||||
|
- [x] ARM64 (Apple silicon)
|
||||||
- [x] Windows
|
- [x] Windows
|
||||||
- [x] x86
|
- [x] x86
|
||||||
- [x] x86-64
|
- [x] x86-64
|
||||||
|
- [x] arm64
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
@ -234,12 +266,13 @@ LDFLAGS+= $(pkg-config --libs libcpuinfo)
|
||||||
- [x] Using `/proc/cpuinfo` on ARM
|
- [x] Using `/proc/cpuinfo` on ARM
|
||||||
- [x] Using `ro.chipname`, `ro.board.platform`, `ro.product.board`, `ro.mediatek.platform`, `ro.arch` properties (Android)
|
- [x] Using `ro.chipname`, `ro.board.platform`, `ro.product.board`, `ro.mediatek.platform`, `ro.arch` properties (Android)
|
||||||
- [ ] Using kernel log (`dmesg`) on ARM Linux
|
- [ ] Using kernel log (`dmesg`) on ARM Linux
|
||||||
|
- [x] Using Windows registry on ARM64 Windows
|
||||||
- Vendor and microarchitecture detection
|
- Vendor and microarchitecture detection
|
||||||
- [x] Intel-designed x86/x86-64 cores (up to Sunny Cove, Goldmont Plus, and Knights Mill)
|
- [x] Intel-designed x86/x86-64 cores (up to Sunny Cove, Goldmont Plus, and Knights Mill)
|
||||||
- [x] AMD-designed x86/x86-64 cores (up to Puma/Jaguar and Zen 2)
|
- [x] AMD-designed x86/x86-64 cores (up to Puma/Jaguar and Zen 2)
|
||||||
- [ ] VIA-designed x86/x86-64 cores
|
- [ ] VIA-designed x86/x86-64 cores
|
||||||
- [ ] Other x86 cores (DM&P, RDC, Transmeta, Cyrix, Rise)
|
- [ ] Other x86 cores (DM&P, RDC, Transmeta, Cyrix, Rise)
|
||||||
- [x] ARM-designed ARM cores (up to Cortex-A55, Cortex-A77, and Neoverse E1/N1)
|
- [x] ARM-designed ARM cores (up to Cortex-A55, Cortex-A77, and Neoverse E1/V1/N2/V2)
|
||||||
- [x] Qualcomm-designed ARM cores (Scorpion, Krait, and Kryo)
|
- [x] Qualcomm-designed ARM cores (Scorpion, Krait, and Kryo)
|
||||||
- [x] Nvidia-designed ARM cores (Denver and Carmel)
|
- [x] Nvidia-designed ARM cores (Denver and Carmel)
|
||||||
- [x] Samsung-designed ARM cores (Exynos)
|
- [x] Samsung-designed ARM cores (Exynos)
|
||||||
|
@ -256,6 +289,7 @@ LDFLAGS+= $(pkg-config --libs libcpuinfo)
|
||||||
- [x] Using `/proc/self/auxv` (Android/ARM)
|
- [x] Using `/proc/self/auxv` (Android/ARM)
|
||||||
- [ ] Using instruction probing on ARM (Linux)
|
- [ ] Using instruction probing on ARM (Linux)
|
||||||
- [ ] Using CPUID registers on ARM64 (Linux)
|
- [ ] Using CPUID registers on ARM64 (Linux)
|
||||||
|
- [x] Using IsProcessorFeaturePresent on ARM64 Windows
|
||||||
- Cache detection
|
- Cache detection
|
||||||
- [x] Using CPUID leaf 0x00000002 (x86/x86-64)
|
- [x] Using CPUID leaf 0x00000002 (x86/x86-64)
|
||||||
- [x] Using CPUID leaf 0x00000004 (non-AMD x86/x86-64)
|
- [x] Using CPUID leaf 0x00000004 (non-AMD x86/x86-64)
|
||||||
|
@ -267,6 +301,7 @@ LDFLAGS+= $(pkg-config --libs libcpuinfo)
|
||||||
- [x] Using `sysctlbyname` (Mach)
|
- [x] Using `sysctlbyname` (Mach)
|
||||||
- [x] Using sysfs `typology` directories (ARM/Linux)
|
- [x] Using sysfs `typology` directories (ARM/Linux)
|
||||||
- [ ] Using sysfs `cache` directories (Linux)
|
- [ ] Using sysfs `cache` directories (Linux)
|
||||||
|
- [x] Using `GetLogicalProcessorInformationEx` on ARM64 Windows
|
||||||
- TLB detection
|
- TLB detection
|
||||||
- [x] Using CPUID leaf 0x00000002 (x86/x86-64)
|
- [x] Using CPUID leaf 0x00000002 (x86/x86-64)
|
||||||
- [ ] Using CPUID leaves 0x80000005-0x80000006 and 0x80000019 (AMD x86/x86-64)
|
- [ ] Using CPUID leaves 0x80000005-0x80000006 and 0x80000019 (AMD x86/x86-64)
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)
|
||||||
|
|
||||||
|
PROJECT(googlebenchmark-download NONE)
|
||||||
|
|
||||||
|
INCLUDE(ExternalProject)
|
||||||
|
ExternalProject_Add(googlebenchmark
|
||||||
|
URL https://github.com/google/benchmark/archive/v1.6.1.zip
|
||||||
|
URL_HASH SHA256=367e963b8620080aff8c831e24751852cffd1f74ea40f25d9cc1b667a9dd5e45
|
||||||
|
SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googlebenchmark"
|
||||||
|
BINARY_DIR "${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark"
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
TEST_COMMAND ""
|
||||||
|
)
|
|
@ -0,0 +1,15 @@
|
||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)
|
||||||
|
|
||||||
|
PROJECT(googletest-download NONE)
|
||||||
|
|
||||||
|
INCLUDE(ExternalProject)
|
||||||
|
ExternalProject_Add(googletest
|
||||||
|
URL https://github.com/google/googletest/archive/release-1.11.0.zip
|
||||||
|
URL_HASH SHA256=353571c2440176ded91c2de6d6cd88ddd41401d14692ec1f99e35d013feda55a
|
||||||
|
SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googletest"
|
||||||
|
BINARY_DIR "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest"
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
TEST_COMMAND ""
|
||||||
|
)
|
|
@ -0,0 +1,12 @@
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||||
|
file(GLOB CONFIG_FILES "${_DIR}/cpuinfo-config-*.cmake")
|
||||||
|
foreach(f ${CONFIG_FILES})
|
||||||
|
include(${f})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# ${_DIR}/cpuinfo-targets-*.cmake will be included here
|
||||||
|
include("${_DIR}/cpuinfo-targets.cmake")
|
||||||
|
|
||||||
|
check_required_components(@PROJECT_NAME@)
|
|
@ -30,36 +30,85 @@
|
||||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\arm\cache.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\arm\uarch.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\arm\windows\init-by-logical-sys-info.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\arm\windows\init.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="deps\clog\src\clog.c" />
|
<ClCompile Include="deps\clog\src\clog.c" />
|
||||||
<ClCompile Include="src\api.c" />
|
<ClCompile Include="src\api.c" />
|
||||||
<ClCompile Include="src\cache.c" />
|
<ClCompile Include="src\cache.c" />
|
||||||
<ClCompile Include="src\init.c" />
|
<ClCompile Include="src\init.c" />
|
||||||
<ClCompile Include="src\x86\cache\descriptor.c" />
|
<ClCompile Include="src\x86\cache\descriptor.c">
|
||||||
<ClCompile Include="src\x86\cache\deterministic.c" />
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="src\x86\cache\init.c" />
|
</ClCompile>
|
||||||
<ClCompile Include="src\x86\info.c" />
|
<ClCompile Include="src\x86\cache\deterministic.c">
|
||||||
<ClCompile Include="src\x86\init.c" />
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="src\x86\isa.c" />
|
</ClCompile>
|
||||||
<ClCompile Include="src\x86\name.c" />
|
<ClCompile Include="src\x86\cache\init.c">
|
||||||
<ClCompile Include="src\x86\topology.c" />
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
<ClCompile Include="src\x86\uarch.c" />
|
</ClCompile>
|
||||||
<ClCompile Include="src\x86\vendor.c" />
|
<ClCompile Include="src\x86\info.c">
|
||||||
<ClCompile Include="src\x86\windows\init.c" />
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\x86\init.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\x86\isa.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\x86\name.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\x86\topology.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\x86\uarch.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\x86\vendor.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\x86\windows\init.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\arm\api.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\arm\midr.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\arm\windows\windows-arm-init.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="deps\clog\include\clog.h" />
|
<ClInclude Include="deps\clog\include\clog.h" />
|
||||||
<ClInclude Include="include\cpuinfo.h" />
|
<ClInclude Include="include\cpuinfo.h" />
|
||||||
<ClInclude Include="src\cpuinfo\common.h" />
|
<ClInclude Include="src\cpuinfo\common.h" />
|
||||||
<ClInclude Include="src\cpuinfo\internal-api.h" />
|
<ClInclude Include="src\cpuinfo\internal-api.h" />
|
||||||
<ClInclude Include="src\cpuinfo\log.h" />
|
<ClInclude Include="src\cpuinfo\log.h" />
|
||||||
<ClInclude Include="src\cpuinfo\utils.h" />
|
<ClInclude Include="src\cpuinfo\utils.h" />
|
||||||
<ClInclude Include="src\x86\api.h" />
|
<ClInclude Include="src\x86\api.h">
|
||||||
<ClInclude Include="src\x86\cpuid.h" />
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
<ClInclude Include="src\x86\windows\api.h" />
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\x86\cpuid.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\x86\windows\api.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemDefinitionGroup>
|
<ItemDefinitionGroup>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>CPUINFO_LOG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;$(ProjectDir)deps\clog\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;$(ProjectDir)deps\clog\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
<Filter Include="clog">
|
<Filter Include="clog">
|
||||||
<UniqueIdentifier>{7f0aba4c-ca06-4a7b-aed1-4f1e6976e839}</UniqueIdentifier>
|
<UniqueIdentifier>{7f0aba4c-ca06-4a7b-aed1-4f1e6976e839}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="arm">
|
||||||
|
<UniqueIdentifier>{ac4549d3-f60f-4e60-bf43-86d1c253cf3f}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="arm\windows">
|
||||||
|
<UniqueIdentifier>{41fcb23a-e77b-4b5c-8238-e9b92bf1f3c6}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\x86\isa.c">
|
<ClCompile Include="src\x86\isa.c">
|
||||||
|
@ -57,6 +63,18 @@
|
||||||
<ClCompile Include="deps\clog\src\clog.c">
|
<ClCompile Include="deps\clog\src\clog.c">
|
||||||
<Filter>clog</Filter>
|
<Filter>clog</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\arm\cache.c">
|
||||||
|
<Filter>arm</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\arm\uarch.c">
|
||||||
|
<Filter>arm</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\arm\windows\init.c">
|
||||||
|
<Filter>arm\windows</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\arm\windows\init-by-logical-sys-info.c">
|
||||||
|
<Filter>arm\windows</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\x86\api.h">
|
<ClInclude Include="src\x86\api.h">
|
||||||
|
@ -84,5 +102,14 @@
|
||||||
<ClInclude Include="deps\clog\include\clog.h">
|
<ClInclude Include="deps\clog\include\clog.h">
|
||||||
<Filter>clog</Filter>
|
<Filter>clog</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\arm\api.h">
|
||||||
|
<Filter>arm</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\arm\midr.h">
|
||||||
|
<Filter>arm</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\arm\windows\windows-arm-init.h">
|
||||||
|
<Filter>arm\windows</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -1,5 +1,7 @@
|
||||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR)
|
CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR)
|
||||||
|
|
||||||
|
INCLUDE(GNUInstallDirs)
|
||||||
|
|
||||||
# ---[ Project and semantic versioning.
|
# ---[ Project and semantic versioning.
|
||||||
PROJECT(clog C CXX)
|
PROJECT(clog C CXX)
|
||||||
|
|
||||||
|
@ -11,6 +13,14 @@ IF(ANDROID)
|
||||||
ELSE()
|
ELSE()
|
||||||
OPTION(CLOG_LOG_TO_STDIO "Log errors, warnings, and information to stdout/stderr" ON)
|
OPTION(CLOG_LOG_TO_STDIO "Log errors, warnings, and information to stdout/stderr" ON)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
OPTION(CLOG_BUILD_TESTS "Build clog tests" ON)
|
||||||
|
OPTION(USE_SYSTEM_LIBS "Use system libraries instead of downloading and building them" OFF)
|
||||||
|
OPTION(USE_SYSTEM_GOOGLETEST "Use system Google Test library instead of downloading and building it" ${USE_SYSTEM_LIBS})
|
||||||
|
|
||||||
|
# ---[ CMake options
|
||||||
|
IF(CLOG_BUILD_TESTS)
|
||||||
|
ENABLE_TESTING()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
MACRO(CLOG_TARGET_RUNTIME_LIBRARY target)
|
MACRO(CLOG_TARGET_RUNTIME_LIBRARY target)
|
||||||
IF(MSVC AND NOT CLOG_RUNTIME_TYPE STREQUAL "default")
|
IF(MSVC AND NOT CLOG_RUNTIME_TYPE STREQUAL "default")
|
||||||
|
@ -24,6 +34,26 @@ MACRO(CLOG_TARGET_RUNTIME_LIBRARY target)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDMACRO()
|
ENDMACRO()
|
||||||
|
|
||||||
|
# ---[ Download deps
|
||||||
|
SET(CONFU_DEPENDENCIES_SOURCE_DIR ${CMAKE_SOURCE_DIR}/deps
|
||||||
|
CACHE PATH "Confu-style dependencies source directory")
|
||||||
|
SET(CONFU_DEPENDENCIES_BINARY_DIR ${CMAKE_BINARY_DIR}/deps
|
||||||
|
CACHE PATH "Confu-style dependencies binary directory")
|
||||||
|
|
||||||
|
IF(CLOG_BUILD_TESTS)
|
||||||
|
IF(USE_SYSTEM_GOOGLETEST)
|
||||||
|
FIND_PACKAGE(GTest REQUIRED)
|
||||||
|
ELSEIF(NOT DEFINED GOOGLETEST_SOURCE_DIR)
|
||||||
|
MESSAGE(STATUS "Downloading Google Test to ${CONFU_DEPENDENCIES_SOURCE_DIR}/googletest (define GOOGLETEST_SOURCE_DIR to avoid it)")
|
||||||
|
CONFIGURE_FILE(cmake/DownloadGoogleTest.cmake "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest-download/CMakeLists.txt")
|
||||||
|
EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
|
||||||
|
WORKING_DIRECTORY "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest-download")
|
||||||
|
EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
|
||||||
|
WORKING_DIRECTORY "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest-download")
|
||||||
|
SET(GOOGLETEST_SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googletest" CACHE STRING "Google Test source directory")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
# ---[ clog library
|
# ---[ clog library
|
||||||
ADD_LIBRARY(clog STATIC src/clog.c)
|
ADD_LIBRARY(clog STATIC src/clog.c)
|
||||||
SET_TARGET_PROPERTIES(clog PROPERTIES
|
SET_TARGET_PROPERTIES(clog PROPERTIES
|
||||||
|
@ -31,7 +61,7 @@ SET_TARGET_PROPERTIES(clog PROPERTIES
|
||||||
C_EXTENSIONS NO)
|
C_EXTENSIONS NO)
|
||||||
CLOG_TARGET_RUNTIME_LIBRARY(clog)
|
CLOG_TARGET_RUNTIME_LIBRARY(clog)
|
||||||
SET_TARGET_PROPERTIES(clog PROPERTIES PUBLIC_HEADER include/clog.h)
|
SET_TARGET_PROPERTIES(clog PROPERTIES PUBLIC_HEADER include/clog.h)
|
||||||
TARGET_INCLUDE_DIRECTORIES(clog BEFORE PUBLIC include)
|
TARGET_INCLUDE_DIRECTORIES(clog PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
IF(CLOG_LOG_TO_STDIO)
|
IF(CLOG_LOG_TO_STDIO)
|
||||||
TARGET_COMPILE_DEFINITIONS(clog PRIVATE CLOG_LOG_TO_STDIO=1)
|
TARGET_COMPILE_DEFINITIONS(clog PRIVATE CLOG_LOG_TO_STDIO=1)
|
||||||
ELSE()
|
ELSE()
|
||||||
|
@ -40,3 +70,32 @@ ENDIF()
|
||||||
IF(ANDROID AND NOT CLOG_LOG_TO_STDIO)
|
IF(ANDROID AND NOT CLOG_LOG_TO_STDIO)
|
||||||
TARGET_LINK_LIBRARIES(clog PRIVATE log)
|
TARGET_LINK_LIBRARIES(clog PRIVATE log)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
ADD_LIBRARY(cpuinfo::clog ALIAS clog)
|
||||||
|
|
||||||
|
INSTALL(TARGETS clog
|
||||||
|
EXPORT cpuinfo-targets
|
||||||
|
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||||
|
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||||
|
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||||
|
|
||||||
|
# ---[ clog tests
|
||||||
|
IF(CLOG_BUILD_TESTS)
|
||||||
|
# ---[ Build google test
|
||||||
|
IF(NOT TARGET gtest AND NOT USE_SYSTEM_GOOGLETEST)
|
||||||
|
IF(MSVC AND NOT CLOG_RUNTIME_TYPE STREQUAL "static")
|
||||||
|
SET(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
ENDIF()
|
||||||
|
ADD_SUBDIRECTORY(
|
||||||
|
"${GOOGLETEST_SOURCE_DIR}"
|
||||||
|
"${CONFU_DEPENDENCIES_BINARY_DIR}/googletest")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(clog-test test/clog.cc)
|
||||||
|
SET_TARGET_PROPERTIES(clog-test PROPERTIES
|
||||||
|
CXX_STANDARD 11
|
||||||
|
CXX_EXTENSIONS NO)
|
||||||
|
CLOG_TARGET_RUNTIME_LIBRARY(clog-test)
|
||||||
|
TARGET_LINK_LIBRARIES(clog-test PRIVATE clog gtest gtest_main)
|
||||||
|
ADD_TEST(clog-test clog-test)
|
||||||
|
ENDIF()
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __hexagon__
|
||||||
|
#include <qurt_printf.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CLOG_LOG_TO_STDIO
|
#ifndef CLOG_LOG_TO_STDIO
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
|
@ -102,12 +105,14 @@ void clog_vlog_fatal(const char* module, const char* format, va_list args) {
|
||||||
out_buffer = heap_buffer;
|
out_buffer = heap_buffer;
|
||||||
}
|
}
|
||||||
out_buffer[prefix_chars + format_chars] = '\n';
|
out_buffer[prefix_chars + format_chars] = '\n';
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
DWORD bytes_written;
|
DWORD bytes_written;
|
||||||
WriteFile(
|
WriteFile(
|
||||||
GetStdHandle(STD_ERROR_HANDLE),
|
GetStdHandle(STD_ERROR_HANDLE),
|
||||||
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
||||||
&bytes_written, NULL);
|
&bytes_written, NULL);
|
||||||
|
#elif defined(__hexagon__)
|
||||||
|
qurt_printf("%s", out_buffer);
|
||||||
#else
|
#else
|
||||||
write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
||||||
#endif
|
#endif
|
||||||
|
@ -178,12 +183,14 @@ void clog_vlog_error(const char* module, const char* format, va_list args) {
|
||||||
out_buffer = heap_buffer;
|
out_buffer = heap_buffer;
|
||||||
}
|
}
|
||||||
out_buffer[prefix_chars + format_chars] = '\n';
|
out_buffer[prefix_chars + format_chars] = '\n';
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
DWORD bytes_written;
|
DWORD bytes_written;
|
||||||
WriteFile(
|
WriteFile(
|
||||||
GetStdHandle(STD_ERROR_HANDLE),
|
GetStdHandle(STD_ERROR_HANDLE),
|
||||||
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
||||||
&bytes_written, NULL);
|
&bytes_written, NULL);
|
||||||
|
#elif defined(__hexagon__)
|
||||||
|
qurt_printf("%s", out_buffer);
|
||||||
#else
|
#else
|
||||||
write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
||||||
#endif
|
#endif
|
||||||
|
@ -254,12 +261,14 @@ void clog_vlog_warning(const char* module, const char* format, va_list args) {
|
||||||
out_buffer = heap_buffer;
|
out_buffer = heap_buffer;
|
||||||
}
|
}
|
||||||
out_buffer[prefix_chars + format_chars] = '\n';
|
out_buffer[prefix_chars + format_chars] = '\n';
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
DWORD bytes_written;
|
DWORD bytes_written;
|
||||||
WriteFile(
|
WriteFile(
|
||||||
GetStdHandle(STD_ERROR_HANDLE),
|
GetStdHandle(STD_ERROR_HANDLE),
|
||||||
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
||||||
&bytes_written, NULL);
|
&bytes_written, NULL);
|
||||||
|
#elif defined(__hexagon__)
|
||||||
|
qurt_printf("%s", out_buffer);
|
||||||
#else
|
#else
|
||||||
write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
write(STDERR_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
||||||
#endif
|
#endif
|
||||||
|
@ -330,12 +339,14 @@ void clog_vlog_info(const char* module, const char* format, va_list args) {
|
||||||
out_buffer = heap_buffer;
|
out_buffer = heap_buffer;
|
||||||
}
|
}
|
||||||
out_buffer[prefix_chars + format_chars] = '\n';
|
out_buffer[prefix_chars + format_chars] = '\n';
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
DWORD bytes_written;
|
DWORD bytes_written;
|
||||||
WriteFile(
|
WriteFile(
|
||||||
GetStdHandle(STD_OUTPUT_HANDLE),
|
GetStdHandle(STD_OUTPUT_HANDLE),
|
||||||
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
||||||
&bytes_written, NULL);
|
&bytes_written, NULL);
|
||||||
|
#elif defined(__hexagon__)
|
||||||
|
qurt_printf("%s", out_buffer);
|
||||||
#else
|
#else
|
||||||
write(STDOUT_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
write(STDOUT_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
||||||
#endif
|
#endif
|
||||||
|
@ -406,12 +417,14 @@ void clog_vlog_debug(const char* module, const char* format, va_list args) {
|
||||||
out_buffer = heap_buffer;
|
out_buffer = heap_buffer;
|
||||||
}
|
}
|
||||||
out_buffer[prefix_chars + format_chars] = '\n';
|
out_buffer[prefix_chars + format_chars] = '\n';
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
DWORD bytes_written;
|
DWORD bytes_written;
|
||||||
WriteFile(
|
WriteFile(
|
||||||
GetStdHandle(STD_OUTPUT_HANDLE),
|
GetStdHandle(STD_OUTPUT_HANDLE),
|
||||||
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH,
|
||||||
&bytes_written, NULL);
|
&bytes_written, NULL);
|
||||||
|
#elif defined(__hexagon__)
|
||||||
|
qurt_printf("%s", out_buffer);
|
||||||
#else
|
#else
|
||||||
write(STDOUT_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
write(STDOUT_FILENO, out_buffer, prefix_chars + format_chars + CLOG_SUFFIX_LENGTH);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,37 +7,35 @@
|
||||||
|
|
||||||
#include <cpuinfo.h>
|
#include <cpuinfo.h>
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(CPUINFO_MOCK) || !(CPUINFO_MOCK)
|
#if !defined(CPUINFO_MOCK) || !(CPUINFO_MOCK)
|
||||||
#error This header is intended only for test use
|
#error This header is intended only for test use
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if CPUINFO_ARCH_ARM
|
#if CPUINFO_ARCH_ARM
|
||||||
void CPUINFO_ABI cpuinfo_set_fpsid(uint32_t fpsid);
|
void CPUINFO_ABI cpuinfo_set_fpsid(uint32_t fpsid);
|
||||||
void CPUINFO_ABI cpuinfo_set_wcid(uint32_t wcid);
|
void CPUINFO_ABI cpuinfo_set_wcid(uint32_t wcid);
|
||||||
#endif /* CPUINFO_ARCH_ARM */
|
#endif /* CPUINFO_ARCH_ARM */
|
||||||
|
|
||||||
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
|
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
|
||||||
struct cpuinfo_mock_cpuid {
|
struct cpuinfo_mock_cpuid {
|
||||||
uint32_t input_eax;
|
uint32_t input_eax;
|
||||||
uint32_t input_ecx;
|
uint32_t input_ecx;
|
||||||
uint32_t eax;
|
uint32_t eax;
|
||||||
uint32_t ebx;
|
uint32_t ebx;
|
||||||
uint32_t ecx;
|
uint32_t ecx;
|
||||||
uint32_t edx;
|
uint32_t edx;
|
||||||
};
|
};
|
||||||
|
|
||||||
void CPUINFO_ABI cpuinfo_mock_set_cpuid(struct cpuinfo_mock_cpuid* dump, size_t entries);
|
void CPUINFO_ABI cpuinfo_mock_set_cpuid(struct cpuinfo_mock_cpuid* dump, size_t entries);
|
||||||
void CPUINFO_ABI cpuinfo_mock_get_cpuid(uint32_t eax, uint32_t regs[4]);
|
void CPUINFO_ABI cpuinfo_mock_get_cpuid(uint32_t eax, uint32_t regs[4]);
|
||||||
void CPUINFO_ABI cpuinfo_mock_get_cpuidex(uint32_t eax, uint32_t ecx, uint32_t regs[4]);
|
void CPUINFO_ABI cpuinfo_mock_get_cpuidex(uint32_t eax, uint32_t ecx, uint32_t regs[4]);
|
||||||
#endif /* CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64 */
|
#endif /* CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64 */
|
||||||
|
|
||||||
struct cpuinfo_mock_file {
|
struct cpuinfo_mock_file {
|
||||||
|
@ -53,22 +51,22 @@ struct cpuinfo_mock_property {
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
void CPUINFO_ABI cpuinfo_mock_filesystem(struct cpuinfo_mock_file* files);
|
void CPUINFO_ABI cpuinfo_mock_filesystem(struct cpuinfo_mock_file* files);
|
||||||
int CPUINFO_ABI cpuinfo_mock_open(const char* path, int oflag);
|
int CPUINFO_ABI cpuinfo_mock_open(const char* path, int oflag);
|
||||||
int CPUINFO_ABI cpuinfo_mock_close(int fd);
|
int CPUINFO_ABI cpuinfo_mock_close(int fd);
|
||||||
ssize_t CPUINFO_ABI cpuinfo_mock_read(int fd, void* buffer, size_t capacity);
|
ssize_t CPUINFO_ABI cpuinfo_mock_read(int fd, void* buffer, size_t capacity);
|
||||||
|
|
||||||
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
||||||
void CPUINFO_ABI cpuinfo_set_hwcap(uint32_t hwcap);
|
void CPUINFO_ABI cpuinfo_set_hwcap(uint32_t hwcap);
|
||||||
#endif
|
#endif
|
||||||
#if CPUINFO_ARCH_ARM
|
#if CPUINFO_ARCH_ARM
|
||||||
void CPUINFO_ABI cpuinfo_set_hwcap2(uint32_t hwcap2);
|
void CPUINFO_ABI cpuinfo_set_hwcap2(uint64_t hwcap2);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
void CPUINFO_ABI cpuinfo_mock_android_properties(struct cpuinfo_mock_property* properties);
|
void CPUINFO_ABI cpuinfo_mock_android_properties(struct cpuinfo_mock_property* properties);
|
||||||
void CPUINFO_ABI cpuinfo_mock_gl_renderer(const char* renderer);
|
void CPUINFO_ABI cpuinfo_mock_gl_renderer(const char* renderer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,13 +6,13 @@
|
||||||
#include <cpuinfo/log.h>
|
#include <cpuinfo/log.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <linux/api.h>
|
#include <linux/api.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/syscall.h>
|
#include <unistd.h>
|
||||||
#if !defined(__NR_getcpu)
|
#if !defined(__NR_getcpu)
|
||||||
#include <asm-generic/unistd.h>
|
#include <asm-generic/unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool cpuinfo_is_initialized = false;
|
bool cpuinfo_is_initialized = false;
|
||||||
|
@ -21,55 +21,54 @@ struct cpuinfo_processor* cpuinfo_processors = NULL;
|
||||||
struct cpuinfo_core* cpuinfo_cores = NULL;
|
struct cpuinfo_core* cpuinfo_cores = NULL;
|
||||||
struct cpuinfo_cluster* cpuinfo_clusters = NULL;
|
struct cpuinfo_cluster* cpuinfo_clusters = NULL;
|
||||||
struct cpuinfo_package* cpuinfo_packages = NULL;
|
struct cpuinfo_package* cpuinfo_packages = NULL;
|
||||||
struct cpuinfo_cache* cpuinfo_cache[cpuinfo_cache_level_max] = { NULL };
|
struct cpuinfo_cache* cpuinfo_cache[cpuinfo_cache_level_max] = {NULL};
|
||||||
|
|
||||||
uint32_t cpuinfo_processors_count = 0;
|
uint32_t cpuinfo_processors_count = 0;
|
||||||
uint32_t cpuinfo_cores_count = 0;
|
uint32_t cpuinfo_cores_count = 0;
|
||||||
uint32_t cpuinfo_clusters_count = 0;
|
uint32_t cpuinfo_clusters_count = 0;
|
||||||
uint32_t cpuinfo_packages_count = 0;
|
uint32_t cpuinfo_packages_count = 0;
|
||||||
uint32_t cpuinfo_cache_count[cpuinfo_cache_level_max] = { 0 };
|
uint32_t cpuinfo_cache_count[cpuinfo_cache_level_max] = {0};
|
||||||
uint32_t cpuinfo_max_cache_size = 0;
|
uint32_t cpuinfo_max_cache_size = 0;
|
||||||
|
|
||||||
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
|
||||||
struct cpuinfo_uarch_info* cpuinfo_uarchs = NULL;
|
struct cpuinfo_uarch_info* cpuinfo_uarchs = NULL;
|
||||||
uint32_t cpuinfo_uarchs_count = 0;
|
uint32_t cpuinfo_uarchs_count = 0;
|
||||||
#else
|
#else
|
||||||
struct cpuinfo_uarch_info cpuinfo_global_uarch = { cpuinfo_uarch_unknown };
|
struct cpuinfo_uarch_info cpuinfo_global_uarch = {cpuinfo_uarch_unknown};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
uint32_t cpuinfo_linux_cpu_max = 0;
|
uint32_t cpuinfo_linux_cpu_max = 0;
|
||||||
const struct cpuinfo_processor** cpuinfo_linux_cpu_to_processor_map = NULL;
|
const struct cpuinfo_processor** cpuinfo_linux_cpu_to_processor_map = NULL;
|
||||||
const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_map = NULL;
|
const struct cpuinfo_core** cpuinfo_linux_cpu_to_core_map = NULL;
|
||||||
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
|
||||||
const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map = NULL;
|
const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map = NULL;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
const struct cpuinfo_processor* cpuinfo_get_processors(void) {
|
const struct cpuinfo_processor* cpuinfo_get_processors(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processors");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processors");
|
||||||
}
|
}
|
||||||
return cpuinfo_processors;
|
return cpuinfo_processors;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_core* cpuinfo_get_cores(void) {
|
const struct cpuinfo_core* cpuinfo_get_cores(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "core");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "core");
|
||||||
}
|
}
|
||||||
return cpuinfo_cores;
|
return cpuinfo_cores;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cluster* cpuinfo_get_clusters(void) {
|
const struct cpuinfo_cluster* cpuinfo_get_clusters(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "clusters");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "clusters");
|
||||||
}
|
}
|
||||||
return cpuinfo_clusters;
|
return cpuinfo_clusters;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_package* cpuinfo_get_packages(void) {
|
const struct cpuinfo_package* cpuinfo_get_packages(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "packages");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "packages");
|
||||||
}
|
}
|
||||||
return cpuinfo_packages;
|
return cpuinfo_packages;
|
||||||
|
@ -79,48 +78,48 @@ const struct cpuinfo_uarch_info* cpuinfo_get_uarchs() {
|
||||||
if (!cpuinfo_is_initialized) {
|
if (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarchs");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarchs");
|
||||||
}
|
}
|
||||||
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
|
||||||
return cpuinfo_uarchs;
|
return cpuinfo_uarchs;
|
||||||
#else
|
#else
|
||||||
return &cpuinfo_global_uarch;
|
return &cpuinfo_global_uarch;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_processor* cpuinfo_get_processor(uint32_t index) {
|
const struct cpuinfo_processor* cpuinfo_get_processor(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processor");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processor");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_processors_count) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_processors_count) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_processors[index];
|
return &cpuinfo_processors[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_core* cpuinfo_get_core(uint32_t index) {
|
const struct cpuinfo_core* cpuinfo_get_core(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "core");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "core");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_cores_count) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_cores_count) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_cores[index];
|
return &cpuinfo_cores[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cluster* cpuinfo_get_cluster(uint32_t index) {
|
const struct cpuinfo_cluster* cpuinfo_get_cluster(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "cluster");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "cluster");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_clusters_count) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_clusters_count) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_clusters[index];
|
return &cpuinfo_clusters[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_package* cpuinfo_get_package(uint32_t index) {
|
const struct cpuinfo_package* cpuinfo_get_package(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "package");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "package");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_packages_count) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_packages_count) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_packages[index];
|
return &cpuinfo_packages[index];
|
||||||
|
@ -130,42 +129,42 @@ const struct cpuinfo_uarch_info* cpuinfo_get_uarch(uint32_t index) {
|
||||||
if (!cpuinfo_is_initialized) {
|
if (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarch");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarch");
|
||||||
}
|
}
|
||||||
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_uarchs_count) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_uarchs_count) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_uarchs[index];
|
return &cpuinfo_uarchs[index];
|
||||||
#else
|
#else
|
||||||
if CPUINFO_UNLIKELY(index != 0) {
|
if CPUINFO_UNLIKELY (index != 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_global_uarch;
|
return &cpuinfo_global_uarch;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cpuinfo_get_processors_count(void) {
|
uint32_t cpuinfo_get_processors_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processors_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "processors_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_processors_count;
|
return cpuinfo_processors_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cpuinfo_get_cores_count(void) {
|
uint32_t cpuinfo_get_cores_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "cores_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "cores_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_cores_count;
|
return cpuinfo_cores_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cpuinfo_get_clusters_count(void) {
|
uint32_t cpuinfo_get_clusters_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "clusters_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "clusters_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_clusters_count;
|
return cpuinfo_clusters_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cpuinfo_get_packages_count(void) {
|
uint32_t cpuinfo_get_packages_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "packages_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "packages_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_packages_count;
|
return cpuinfo_packages_count;
|
||||||
|
@ -175,236 +174,243 @@ uint32_t cpuinfo_get_uarchs_count(void) {
|
||||||
if (!cpuinfo_is_initialized) {
|
if (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarchs_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "uarchs_count");
|
||||||
}
|
}
|
||||||
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
|
||||||
return cpuinfo_uarchs_count;
|
return cpuinfo_uarchs_count;
|
||||||
#else
|
#else
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1i_caches(void) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1i_caches(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_caches");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_caches");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache[cpuinfo_cache_level_1i];
|
return cpuinfo_cache[cpuinfo_cache_level_1i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1d_caches(void) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1d_caches(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_caches");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_caches");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache[cpuinfo_cache_level_1d];
|
return cpuinfo_cache[cpuinfo_cache_level_1d];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l2_caches(void) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l2_caches(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_caches");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_caches");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache[cpuinfo_cache_level_2];
|
return cpuinfo_cache[cpuinfo_cache_level_2];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l3_caches(void) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l3_caches(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_caches");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_caches");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache[cpuinfo_cache_level_3];
|
return cpuinfo_cache[cpuinfo_cache_level_3];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l4_caches(void) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l4_caches(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_caches");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_caches");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache[cpuinfo_cache_level_4];
|
return cpuinfo_cache[cpuinfo_cache_level_4];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1i_cache(uint32_t index) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1i_cache(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_cache");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_cache");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_cache_count[cpuinfo_cache_level_1i]) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_cache_count[cpuinfo_cache_level_1i]) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_cache[cpuinfo_cache_level_1i][index];
|
return &cpuinfo_cache[cpuinfo_cache_level_1i][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1d_cache(uint32_t index) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l1d_cache(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_cache");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_cache");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_cache_count[cpuinfo_cache_level_1d]) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_cache_count[cpuinfo_cache_level_1d]) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_cache[cpuinfo_cache_level_1d][index];
|
return &cpuinfo_cache[cpuinfo_cache_level_1d][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l2_cache(uint32_t index) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l2_cache(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_cache");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_cache");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_cache_count[cpuinfo_cache_level_2]) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_cache_count[cpuinfo_cache_level_2]) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_cache[cpuinfo_cache_level_2][index];
|
return &cpuinfo_cache[cpuinfo_cache_level_2][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l3_cache(uint32_t index) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l3_cache(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_cache");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_cache");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_cache_count[cpuinfo_cache_level_3]) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_cache_count[cpuinfo_cache_level_3]) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_cache[cpuinfo_cache_level_3][index];
|
return &cpuinfo_cache[cpuinfo_cache_level_3][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l4_cache(uint32_t index) {
|
const struct cpuinfo_cache* CPUINFO_ABI cpuinfo_get_l4_cache(uint32_t index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_cache");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_cache");
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY(index >= cpuinfo_cache_count[cpuinfo_cache_level_4]) {
|
if CPUINFO_UNLIKELY (index >= cpuinfo_cache_count[cpuinfo_cache_level_4]) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &cpuinfo_cache[cpuinfo_cache_level_4][index];
|
return &cpuinfo_cache[cpuinfo_cache_level_4][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPUINFO_ABI cpuinfo_get_l1i_caches_count(void) {
|
uint32_t CPUINFO_ABI cpuinfo_get_l1i_caches_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_caches_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1i_caches_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache_count[cpuinfo_cache_level_1i];
|
return cpuinfo_cache_count[cpuinfo_cache_level_1i];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPUINFO_ABI cpuinfo_get_l1d_caches_count(void) {
|
uint32_t CPUINFO_ABI cpuinfo_get_l1d_caches_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_caches_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l1d_caches_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache_count[cpuinfo_cache_level_1d];
|
return cpuinfo_cache_count[cpuinfo_cache_level_1d];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPUINFO_ABI cpuinfo_get_l2_caches_count(void) {
|
uint32_t CPUINFO_ABI cpuinfo_get_l2_caches_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_caches_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l2_caches_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache_count[cpuinfo_cache_level_2];
|
return cpuinfo_cache_count[cpuinfo_cache_level_2];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPUINFO_ABI cpuinfo_get_l3_caches_count(void) {
|
uint32_t CPUINFO_ABI cpuinfo_get_l3_caches_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_caches_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l3_caches_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache_count[cpuinfo_cache_level_3];
|
return cpuinfo_cache_count[cpuinfo_cache_level_3];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPUINFO_ABI cpuinfo_get_l4_caches_count(void) {
|
uint32_t CPUINFO_ABI cpuinfo_get_l4_caches_count(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_caches_count");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "l4_caches_count");
|
||||||
}
|
}
|
||||||
return cpuinfo_cache_count[cpuinfo_cache_level_4];
|
return cpuinfo_cache_count[cpuinfo_cache_level_4];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPUINFO_ABI cpuinfo_get_max_cache_size(void) {
|
uint32_t CPUINFO_ABI cpuinfo_get_max_cache_size(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "max_cache_size");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "max_cache_size");
|
||||||
}
|
}
|
||||||
return cpuinfo_max_cache_size;
|
return cpuinfo_max_cache_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_processor* CPUINFO_ABI cpuinfo_get_current_processor(void) {
|
const struct cpuinfo_processor* CPUINFO_ABI cpuinfo_get_current_processor(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_processor");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_processor");
|
||||||
}
|
}
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
/* Initializing this variable silences a MemorySanitizer error. */
|
/* Initializing this variable silences a MemorySanitizer error. */
|
||||||
unsigned cpu = 0;
|
unsigned cpu = 0;
|
||||||
if CPUINFO_UNLIKELY(syscall(__NR_getcpu, &cpu, NULL, NULL) != 0) {
|
if CPUINFO_UNLIKELY (syscall(__NR_getcpu, &cpu, NULL, NULL) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY((uint32_t) cpu >= cpuinfo_linux_cpu_max) {
|
if CPUINFO_UNLIKELY ((uint32_t)cpu >= cpuinfo_linux_cpu_max) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cpuinfo_linux_cpu_to_processor_map[cpu];
|
return cpuinfo_linux_cpu_to_processor_map[cpu];
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct cpuinfo_core* CPUINFO_ABI cpuinfo_get_current_core(void) {
|
const struct cpuinfo_core* CPUINFO_ABI cpuinfo_get_current_core(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_core");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_core");
|
||||||
}
|
}
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
/* Initializing this variable silences a MemorySanitizer error. */
|
/* Initializing this variable silences a MemorySanitizer error. */
|
||||||
unsigned cpu = 0;
|
unsigned cpu = 0;
|
||||||
if CPUINFO_UNLIKELY(syscall(__NR_getcpu, &cpu, NULL, NULL) != 0) {
|
if CPUINFO_UNLIKELY (syscall(__NR_getcpu, &cpu, NULL, NULL) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if CPUINFO_UNLIKELY((uint32_t) cpu >= cpuinfo_linux_cpu_max) {
|
if CPUINFO_UNLIKELY ((uint32_t)cpu >= cpuinfo_linux_cpu_max) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return cpuinfo_linux_cpu_to_core_map[cpu];
|
return cpuinfo_linux_cpu_to_core_map[cpu];
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index(void) {
|
uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index(void) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_uarch_index");
|
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_uarch_index");
|
||||||
}
|
}
|
||||||
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (cpuinfo_linux_cpu_to_uarch_index_map == NULL) {
|
if (cpuinfo_linux_cpu_to_uarch_index_map == NULL) {
|
||||||
/* Special case: avoid syscall on systems with only a single type of cores */
|
/* Special case: avoid syscall on systems with only a single
|
||||||
return 0;
|
* type of cores
|
||||||
}
|
*/
|
||||||
|
|
||||||
/* General case */
|
|
||||||
/* Initializing this variable silences a MemorySanitizer error. */
|
|
||||||
unsigned cpu = 0;
|
|
||||||
if CPUINFO_UNLIKELY(syscall(__NR_getcpu, &cpu, NULL, NULL) != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if CPUINFO_UNLIKELY((uint32_t) cpu >= cpuinfo_linux_cpu_max) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return cpuinfo_linux_cpu_to_uarch_index_map[cpu];
|
|
||||||
#else
|
|
||||||
/* Fallback: pretend to be on the big core. */
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
/* Only ARM/ARM64 processors may include cores of different types in the same package. */
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
/* General case */
|
||||||
|
/* Initializing this variable silences a MemorySanitizer error. */
|
||||||
|
unsigned cpu = 0;
|
||||||
|
if CPUINFO_UNLIKELY (syscall(__NR_getcpu, &cpu, NULL, NULL) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if CPUINFO_UNLIKELY ((uint32_t)cpu >= cpuinfo_linux_cpu_max) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return cpuinfo_linux_cpu_to_uarch_index_map[cpu];
|
||||||
|
#else
|
||||||
|
/* Fallback: pretend to be on the big core. */
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/* Only ARM/ARM64/RISCV processors may include cores of different types
|
||||||
|
* in the same package. */
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index_with_default(uint32_t default_uarch_index) {
|
uint32_t CPUINFO_ABI cpuinfo_get_current_uarch_index_with_default(uint32_t default_uarch_index) {
|
||||||
if CPUINFO_UNLIKELY(!cpuinfo_is_initialized) {
|
if CPUINFO_UNLIKELY (!cpuinfo_is_initialized) {
|
||||||
cpuinfo_log_fatal("cpuinfo_get_%s called before cpuinfo is initialized", "current_uarch_index_with_default");
|
cpuinfo_log_fatal(
|
||||||
|
"cpuinfo_get_%s called before cpuinfo is initialized", "current_uarch_index_with_default");
|
||||||
}
|
}
|
||||||
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
|
#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (cpuinfo_linux_cpu_to_uarch_index_map == NULL) {
|
if (cpuinfo_linux_cpu_to_uarch_index_map == NULL) {
|
||||||
/* Special case: avoid syscall on systems with only a single type of cores */
|
/* Special case: avoid syscall on systems with only a single
|
||||||
return 0;
|
* type of cores
|
||||||
}
|
*/
|
||||||
|
|
||||||
/* General case */
|
|
||||||
/* Initializing this variable silences a MemorySanitizer error. */
|
|
||||||
unsigned cpu = 0;
|
|
||||||
if CPUINFO_UNLIKELY(syscall(__NR_getcpu, &cpu, NULL, NULL) != 0) {
|
|
||||||
return default_uarch_index;
|
|
||||||
}
|
|
||||||
if CPUINFO_UNLIKELY((uint32_t) cpu >= cpuinfo_linux_cpu_max) {
|
|
||||||
return default_uarch_index;
|
|
||||||
}
|
|
||||||
return cpuinfo_linux_cpu_to_uarch_index_map[cpu];
|
|
||||||
#else
|
|
||||||
/* Fallback: no API to query current core, use default uarch index. */
|
|
||||||
return default_uarch_index;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
/* Only ARM/ARM64 processors may include cores of different types in the same package. */
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
/* General case */
|
||||||
|
/* Initializing this variable silences a MemorySanitizer error. */
|
||||||
|
unsigned cpu = 0;
|
||||||
|
if CPUINFO_UNLIKELY (syscall(__NR_getcpu, &cpu, NULL, NULL) != 0) {
|
||||||
|
return default_uarch_index;
|
||||||
|
}
|
||||||
|
if CPUINFO_UNLIKELY ((uint32_t)cpu >= cpuinfo_linux_cpu_max) {
|
||||||
|
return default_uarch_index;
|
||||||
|
}
|
||||||
|
return cpuinfo_linux_cpu_to_uarch_index_map[cpu];
|
||||||
|
#else
|
||||||
|
/* Fallback: no API to query current core, use default uarch index. */
|
||||||
|
return default_uarch_index;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/* Only ARM/ARM64/RISCV processors may include cores of different types
|
||||||
|
* in the same package. */
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cpuinfo.h>
|
|
||||||
#include <cpuinfo/common.h>
|
|
||||||
#include <arm/api.h>
|
#include <arm/api.h>
|
||||||
#include <arm/linux/api.h>
|
#include <arm/linux/api.h>
|
||||||
|
#include <cpuinfo.h>
|
||||||
|
#include <cpuinfo/common.h>
|
||||||
|
|
||||||
enum cpuinfo_android_chipset_property {
|
enum cpuinfo_android_chipset_property {
|
||||||
cpuinfo_android_chipset_property_proc_cpuinfo_hardware = 0,
|
cpuinfo_android_chipset_property_proc_cpuinfo_hardware = 0,
|
||||||
|
|
|
@ -1,42 +1,42 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
|
|
||||||
#include <linux/api.h>
|
|
||||||
#include <arm/android/api.h>
|
#include <arm/android/api.h>
|
||||||
#include <arm/linux/api.h>
|
#include <arm/linux/api.h>
|
||||||
#include <cpuinfo/log.h>
|
#include <cpuinfo/log.h>
|
||||||
|
#include <linux/api.h>
|
||||||
|
|
||||||
#if CPUINFO_MOCK
|
#if CPUINFO_MOCK
|
||||||
#include <cpuinfo-mock.h>
|
#include <cpuinfo-mock.h>
|
||||||
|
|
||||||
static struct cpuinfo_mock_property* cpuinfo_mock_properties = NULL;
|
static struct cpuinfo_mock_property* cpuinfo_mock_properties = NULL;
|
||||||
|
|
||||||
void CPUINFO_ABI cpuinfo_mock_android_properties(struct cpuinfo_mock_property* properties) {
|
void CPUINFO_ABI cpuinfo_mock_android_properties(struct cpuinfo_mock_property* properties) {
|
||||||
cpuinfo_log_info("Android properties mocking enabled");
|
cpuinfo_log_info("Android properties mocking enabled");
|
||||||
cpuinfo_mock_properties = properties;
|
cpuinfo_mock_properties = properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cpuinfo_android_property_get(const char* key, char* value) {
|
static int cpuinfo_android_property_get(const char* key, char* value) {
|
||||||
if (cpuinfo_mock_properties != NULL) {
|
if (cpuinfo_mock_properties != NULL) {
|
||||||
for (const struct cpuinfo_mock_property* prop = cpuinfo_mock_properties; prop->key != NULL; prop++) {
|
for (const struct cpuinfo_mock_property* prop = cpuinfo_mock_properties; prop->key != NULL; prop++) {
|
||||||
if (strncmp(key, prop->key, CPUINFO_BUILD_PROP_NAME_MAX) == 0) {
|
if (strncmp(key, prop->key, CPUINFO_BUILD_PROP_NAME_MAX) == 0) {
|
||||||
strncpy(value, prop->value, CPUINFO_BUILD_PROP_VALUE_MAX);
|
strncpy(value, prop->value, CPUINFO_BUILD_PROP_VALUE_MAX);
|
||||||
return (int) strnlen(prop->value, CPUINFO_BUILD_PROP_VALUE_MAX);
|
return (int)strnlen(prop->value, CPUINFO_BUILD_PROP_VALUE_MAX);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*value = '\0';
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
*value = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
static inline int cpuinfo_android_property_get(const char* key, char* value) {
|
static inline int cpuinfo_android_property_get(const char* key, char* value) {
|
||||||
return __system_property_get(key, value);
|
return __system_property_get(key, value);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void cpuinfo_arm_android_parse_properties(struct cpuinfo_android_properties properties[restrict static 1]) {
|
void cpuinfo_arm_android_parse_properties(struct cpuinfo_android_properties properties[restrict static 1]) {
|
||||||
|
@ -50,18 +50,17 @@ void cpuinfo_arm_android_parse_properties(struct cpuinfo_android_properties prop
|
||||||
|
|
||||||
const int ro_mediatek_platform_length =
|
const int ro_mediatek_platform_length =
|
||||||
cpuinfo_android_property_get("ro.mediatek.platform", properties->ro_mediatek_platform);
|
cpuinfo_android_property_get("ro.mediatek.platform", properties->ro_mediatek_platform);
|
||||||
cpuinfo_log_debug("read ro.mediatek.platform = \"%.*s\"",
|
cpuinfo_log_debug(
|
||||||
ro_mediatek_platform_length, properties->ro_mediatek_platform);
|
"read ro.mediatek.platform = \"%.*s\"", ro_mediatek_platform_length, properties->ro_mediatek_platform);
|
||||||
|
|
||||||
const int ro_arch_length =
|
const int ro_arch_length = cpuinfo_android_property_get("ro.arch", properties->ro_arch);
|
||||||
cpuinfo_android_property_get("ro.arch", properties->ro_arch);
|
|
||||||
cpuinfo_log_debug("read ro.arch = \"%.*s\"", ro_arch_length, properties->ro_arch);
|
cpuinfo_log_debug("read ro.arch = \"%.*s\"", ro_arch_length, properties->ro_arch);
|
||||||
|
|
||||||
const int ro_chipname_length =
|
const int ro_chipname_length = cpuinfo_android_property_get("ro.chipname", properties->ro_chipname);
|
||||||
cpuinfo_android_property_get("ro.chipname", properties->ro_chipname);
|
|
||||||
cpuinfo_log_debug("read ro.chipname = \"%.*s\"", ro_chipname_length, properties->ro_chipname);
|
cpuinfo_log_debug("read ro.chipname = \"%.*s\"", ro_chipname_length, properties->ro_chipname);
|
||||||
|
|
||||||
const int ro_hardware_chipname_length =
|
const int ro_hardware_chipname_length =
|
||||||
cpuinfo_android_property_get("ro.hardware.chipname", properties->ro_hardware_chipname);
|
cpuinfo_android_property_get("ro.hardware.chipname", properties->ro_hardware_chipname);
|
||||||
cpuinfo_log_debug("read ro.hardware.chipname = \"%.*s\"", ro_hardware_chipname_length, properties->ro_hardware_chipname);
|
cpuinfo_log_debug(
|
||||||
|
"read ro.hardware.chipname = \"%.*s\"", ro_hardware_chipname_length, properties->ro_hardware_chipname);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum cpuinfo_arm_chipset_vendor {
|
||||||
cpuinfo_arm_chipset_vendor_spreadtrum,
|
cpuinfo_arm_chipset_vendor_spreadtrum,
|
||||||
cpuinfo_arm_chipset_vendor_telechips,
|
cpuinfo_arm_chipset_vendor_telechips,
|
||||||
cpuinfo_arm_chipset_vendor_texas_instruments,
|
cpuinfo_arm_chipset_vendor_texas_instruments,
|
||||||
|
cpuinfo_arm_chipset_vendor_unisoc,
|
||||||
cpuinfo_arm_chipset_vendor_wondermedia,
|
cpuinfo_arm_chipset_vendor_wondermedia,
|
||||||
cpuinfo_arm_chipset_vendor_max,
|
cpuinfo_arm_chipset_vendor_max,
|
||||||
};
|
};
|
||||||
|
@ -62,6 +63,8 @@ enum cpuinfo_arm_chipset_series {
|
||||||
cpuinfo_arm_chipset_series_spreadtrum_sc,
|
cpuinfo_arm_chipset_series_spreadtrum_sc,
|
||||||
cpuinfo_arm_chipset_series_telechips_tcc,
|
cpuinfo_arm_chipset_series_telechips_tcc,
|
||||||
cpuinfo_arm_chipset_series_texas_instruments_omap,
|
cpuinfo_arm_chipset_series_texas_instruments_omap,
|
||||||
|
cpuinfo_arm_chipset_series_unisoc_t,
|
||||||
|
cpuinfo_arm_chipset_series_unisoc_ums,
|
||||||
cpuinfo_arm_chipset_series_wondermedia_wm,
|
cpuinfo_arm_chipset_series_wondermedia_wm,
|
||||||
cpuinfo_arm_chipset_series_max,
|
cpuinfo_arm_chipset_series_max,
|
||||||
};
|
};
|
||||||
|
@ -78,45 +81,47 @@ struct cpuinfo_arm_chipset {
|
||||||
#define CPUINFO_ARM_CHIPSET_NAME_MAX CPUINFO_PACKAGE_NAME_MAX
|
#define CPUINFO_ARM_CHIPSET_NAME_MAX CPUINFO_PACKAGE_NAME_MAX
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
CPUINFO_INTERNAL void cpuinfo_arm_chipset_to_string(
|
CPUINFO_INTERNAL void cpuinfo_arm_chipset_to_string(
|
||||||
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
||||||
char name[restrict static CPUINFO_ARM_CHIPSET_NAME_MAX]);
|
char name[restrict static CPUINFO_ARM_CHIPSET_NAME_MAX]);
|
||||||
|
|
||||||
CPUINFO_INTERNAL void cpuinfo_arm_fixup_chipset(
|
CPUINFO_INTERNAL void cpuinfo_arm_fixup_chipset(
|
||||||
struct cpuinfo_arm_chipset chipset[restrict static 1], uint32_t cores, uint32_t max_cpu_freq_max);
|
struct cpuinfo_arm_chipset chipset[restrict static 1],
|
||||||
|
uint32_t cores,
|
||||||
|
uint32_t max_cpu_freq_max);
|
||||||
|
|
||||||
CPUINFO_INTERNAL void cpuinfo_arm_decode_vendor_uarch(
|
CPUINFO_INTERNAL void cpuinfo_arm_decode_vendor_uarch(
|
||||||
uint32_t midr,
|
uint32_t midr,
|
||||||
#if CPUINFO_ARCH_ARM
|
#if CPUINFO_ARCH_ARM
|
||||||
bool has_vfpv4,
|
bool has_vfpv4,
|
||||||
#endif
|
#endif
|
||||||
enum cpuinfo_vendor vendor[restrict static 1],
|
enum cpuinfo_vendor vendor[restrict static 1],
|
||||||
enum cpuinfo_uarch uarch[restrict static 1]);
|
enum cpuinfo_uarch uarch[restrict static 1]);
|
||||||
|
|
||||||
CPUINFO_INTERNAL void cpuinfo_arm_decode_cache(
|
CPUINFO_INTERNAL void cpuinfo_arm_decode_cache(
|
||||||
enum cpuinfo_uarch uarch,
|
enum cpuinfo_uarch uarch,
|
||||||
uint32_t cluster_cores,
|
uint32_t cluster_cores,
|
||||||
uint32_t midr,
|
uint32_t midr,
|
||||||
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
||||||
uint32_t cluster_id,
|
uint32_t cluster_id,
|
||||||
uint32_t arch_version,
|
uint32_t arch_version,
|
||||||
struct cpuinfo_cache l1i[restrict static 1],
|
struct cpuinfo_cache l1i[restrict static 1],
|
||||||
struct cpuinfo_cache l1d[restrict static 1],
|
struct cpuinfo_cache l1d[restrict static 1],
|
||||||
struct cpuinfo_cache l2[restrict static 1],
|
struct cpuinfo_cache l2[restrict static 1],
|
||||||
struct cpuinfo_cache l3[restrict static 1]);
|
struct cpuinfo_cache l3[restrict static 1]);
|
||||||
|
|
||||||
CPUINFO_INTERNAL uint32_t cpuinfo_arm_compute_max_cache_size(
|
CPUINFO_INTERNAL uint32_t
|
||||||
const struct cpuinfo_processor processor[restrict static 1]);
|
cpuinfo_arm_compute_max_cache_size(const struct cpuinfo_processor processor[restrict static 1]);
|
||||||
#else /* defined(__cplusplus) */
|
#else /* defined(__cplusplus) */
|
||||||
CPUINFO_INTERNAL void cpuinfo_arm_decode_cache(
|
CPUINFO_INTERNAL void cpuinfo_arm_decode_cache(
|
||||||
enum cpuinfo_uarch uarch,
|
enum cpuinfo_uarch uarch,
|
||||||
uint32_t cluster_cores,
|
uint32_t cluster_cores,
|
||||||
uint32_t midr,
|
uint32_t midr,
|
||||||
const struct cpuinfo_arm_chipset chipset[1],
|
const struct cpuinfo_arm_chipset chipset[1],
|
||||||
uint32_t cluster_id,
|
uint32_t cluster_id,
|
||||||
uint32_t arch_version,
|
uint32_t arch_version,
|
||||||
struct cpuinfo_cache l1i[1],
|
struct cpuinfo_cache l1i[1],
|
||||||
struct cpuinfo_cache l1d[1],
|
struct cpuinfo_cache l1d[1],
|
||||||
struct cpuinfo_cache l2[1],
|
struct cpuinfo_cache l2[1],
|
||||||
struct cpuinfo_cache l3[1]);
|
struct cpuinfo_cache l3[1]);
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,50 +1,55 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if CPUINFO_MOCK
|
#if CPUINFO_MOCK
|
||||||
#include <cpuinfo-mock.h>
|
#include <cpuinfo-mock.h>
|
||||||
#endif
|
#endif
|
||||||
#include <arm/linux/api.h>
|
#include <arm/linux/api.h>
|
||||||
#include <arm/linux/cp.h>
|
#include <arm/linux/cp.h>
|
||||||
#include <arm/midr.h>
|
#include <arm/midr.h>
|
||||||
#include <cpuinfo/log.h>
|
#include <cpuinfo/log.h>
|
||||||
|
|
||||||
|
|
||||||
#if CPUINFO_MOCK
|
#if CPUINFO_MOCK
|
||||||
uint32_t cpuinfo_arm_fpsid = 0;
|
uint32_t cpuinfo_arm_fpsid = 0;
|
||||||
uint32_t cpuinfo_arm_mvfr0 = 0;
|
uint32_t cpuinfo_arm_mvfr0 = 0;
|
||||||
uint32_t cpuinfo_arm_wcid = 0;
|
uint32_t cpuinfo_arm_wcid = 0;
|
||||||
|
|
||||||
void cpuinfo_set_fpsid(uint32_t fpsid) {
|
void cpuinfo_set_fpsid(uint32_t fpsid) {
|
||||||
cpuinfo_arm_fpsid = fpsid;
|
cpuinfo_arm_fpsid = fpsid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpuinfo_set_wcid(uint32_t wcid) {
|
void cpuinfo_set_wcid(uint32_t wcid) {
|
||||||
cpuinfo_arm_wcid = wcid;
|
cpuinfo_arm_wcid = wcid;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
||||||
uint32_t features,
|
uint32_t features,
|
||||||
uint32_t features2,
|
uint64_t features2,
|
||||||
uint32_t midr,
|
uint32_t midr,
|
||||||
uint32_t architecture_version,
|
uint32_t architecture_version,
|
||||||
uint32_t architecture_flags,
|
uint32_t architecture_flags,
|
||||||
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
||||||
struct cpuinfo_arm_isa isa[restrict static 1])
|
struct cpuinfo_arm_isa isa[restrict static 1]) {
|
||||||
{
|
if (architecture_version < 8) {
|
||||||
|
const uint32_t armv8_features2_mask = CPUINFO_ARM_LINUX_FEATURE2_AES |
|
||||||
|
CPUINFO_ARM_LINUX_FEATURE2_PMULL | CPUINFO_ARM_LINUX_FEATURE2_SHA1 |
|
||||||
|
CPUINFO_ARM_LINUX_FEATURE2_SHA2 | CPUINFO_ARM_LINUX_FEATURE2_CRC32;
|
||||||
|
if (features2 & armv8_features2_mask) {
|
||||||
|
architecture_version = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (architecture_version >= 8) {
|
if (architecture_version >= 8) {
|
||||||
/*
|
/*
|
||||||
* ARMv7 code running on ARMv8: IDIV, VFP, NEON are always supported,
|
* ARMv7 code running on ARMv8: IDIV, VFP, NEON are always
|
||||||
* but may be not reported in /proc/cpuinfo features.
|
* supported, but may be not reported in /proc/cpuinfo features.
|
||||||
*/
|
*/
|
||||||
isa->armv5e = true;
|
isa->armv5e = true;
|
||||||
isa->armv6 = true;
|
isa->armv6 = true;
|
||||||
isa->armv6k = true;
|
isa->armv6k = true;
|
||||||
isa->armv7 = true;
|
isa->armv7 = true;
|
||||||
isa->armv7mp = true;
|
isa->armv7mp = true;
|
||||||
isa->armv8 = true;
|
isa->armv8 = true;
|
||||||
isa->thumb = true;
|
isa->thumb = true;
|
||||||
isa->thumb2 = true;
|
isa->thumb2 = true;
|
||||||
isa->idiv = true;
|
isa->idiv = true;
|
||||||
isa->vfpv3 = true;
|
isa->vfpv3 = true;
|
||||||
|
@ -54,33 +59,61 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
||||||
isa->neon = true;
|
isa->neon = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NEON FP16 compute extension and VQRDMLAH/VQRDMLSH instructions are not indicated in /proc/cpuinfo.
|
* NEON FP16 compute extension and VQRDMLAH/VQRDMLSH
|
||||||
* Use a MIDR-based heuristic to whitelist processors known to support it:
|
* instructions are not indicated in /proc/cpuinfo. Use a
|
||||||
|
* MIDR-based heuristic to whitelist processors known to support
|
||||||
|
* it:
|
||||||
* - Processors with Cortex-A55 cores
|
* - Processors with Cortex-A55 cores
|
||||||
* - Processors with Cortex-A65 cores
|
|
||||||
* - Processors with Cortex-A75 cores
|
* - Processors with Cortex-A75 cores
|
||||||
* - Processors with Cortex-A76 cores
|
* - Processors with Cortex-A76 cores
|
||||||
* - Processors with Cortex-A77 cores
|
* - Processors with Cortex-A77 cores
|
||||||
|
* - Processors with Cortex-A78 cores
|
||||||
|
* - Processors with Cortex-A510 cores
|
||||||
|
* - Processors with Cortex-A710 cores
|
||||||
|
* - Processors with Cortex-A715 cores
|
||||||
|
* - Processors with Cortex-X1 cores
|
||||||
|
* - Processors with Cortex-X2 cores
|
||||||
|
* - Processors with Cortex-X3 cores
|
||||||
* - Processors with Exynos M4 cores
|
* - Processors with Exynos M4 cores
|
||||||
* - Processors with Exynos M5 cores
|
* - Processors with Exynos M5 cores
|
||||||
* - Neoverse N1 cores
|
* - Neoverse N1 cores
|
||||||
|
* - Neoverse N2 cores
|
||||||
|
* - Neoverse V1 cores
|
||||||
|
* - Neoverse V2 cores
|
||||||
*/
|
*/
|
||||||
if (chipset->series == cpuinfo_arm_chipset_series_samsung_exynos && chipset->model == 9810) {
|
if (chipset->series == cpuinfo_arm_chipset_series_samsung_exynos && chipset->model == 9810) {
|
||||||
/* Only little cores of Exynos 9810 support FP16 & RDM */
|
/* Only little cores of Exynos 9810 support FP16 & RDM
|
||||||
cpuinfo_log_warning("FP16 arithmetics and RDM disabled: only little cores in Exynos 9810 support these extensions");
|
*/
|
||||||
|
cpuinfo_log_warning(
|
||||||
|
"FP16 arithmetics and RDM disabled: only little cores in Exynos 9810 support these extensions");
|
||||||
} else {
|
} else {
|
||||||
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
|
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
|
||||||
case UINT32_C(0x4100D050): /* Cortex-A55 */
|
case UINT32_C(0x4100D050): /* Cortex-A55 */
|
||||||
case UINT32_C(0x4100D060): /* Cortex-A65 */
|
case UINT32_C(0x4100D0A0): /* Cortex-A75 */
|
||||||
case UINT32_C(0x4100D0B0): /* Cortex-A76 */
|
case UINT32_C(0x4100D0B0): /* Cortex-A76 */
|
||||||
case UINT32_C(0x4100D0C0): /* Neoverse N1 */
|
case UINT32_C(0x4100D0C0): /* Neoverse N1 */
|
||||||
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
|
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
|
||||||
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
|
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
|
||||||
case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
|
case UINT32_C(0x4100D400): /* Neoverse V1 */
|
||||||
case UINT32_C(0x51008020): /* Kryo 385 Gold (Cortex-A75) */
|
case UINT32_C(0x4100D410): /* Cortex-A78 */
|
||||||
case UINT32_C(0x51008030): /* Kryo 385 Silver (Cortex-A55) */
|
case UINT32_C(0x4100D440): /* Cortex-X1 */
|
||||||
case UINT32_C(0x51008040): /* Kryo 485 Gold (Cortex-A76) */
|
case UINT32_C(0x4100D460): /* Cortex-A510 */
|
||||||
case UINT32_C(0x51008050): /* Kryo 485 Silver (Cortex-A55) */
|
case UINT32_C(0x4100D470): /* Cortex-A710 */
|
||||||
|
case UINT32_C(0x4100D480): /* Cortex-X2 */
|
||||||
|
case UINT32_C(0x4100D490): /* Neoverse N2 */
|
||||||
|
case UINT32_C(0x4100D4D0): /* Cortex-A715 */
|
||||||
|
case UINT32_C(0x4100D4E0): /* Cortex-X3 */
|
||||||
|
case UINT32_C(0x4100D4F0): /* Neoverse V2 */
|
||||||
|
case UINT32_C(0x4800D400): /* Cortex-A76
|
||||||
|
(HiSilicon) */
|
||||||
|
case UINT32_C(0x51008020): /* Kryo 385 Gold
|
||||||
|
(Cortex-A75) */
|
||||||
|
case UINT32_C(0x51008030): /* Kryo 385 Silver
|
||||||
|
(Cortex-A55) */
|
||||||
|
case UINT32_C(0x51008040): /* Kryo 485 Gold
|
||||||
|
(Cortex-A76) */
|
||||||
|
case UINT32_C(0x51008050): /* Kryo 485 Silver
|
||||||
|
(Cortex-A55) */
|
||||||
case UINT32_C(0x53000030): /* Exynos M4 */
|
case UINT32_C(0x53000030): /* Exynos M4 */
|
||||||
case UINT32_C(0x53000040): /* Exynos M5 */
|
case UINT32_C(0x53000040): /* Exynos M5 */
|
||||||
isa->fp16arith = true;
|
isa->fp16arith = true;
|
||||||
|
@ -91,46 +124,93 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NEON VDOT instructions are not indicated in /proc/cpuinfo.
|
* NEON VDOT instructions are not indicated in /proc/cpuinfo.
|
||||||
* Use a MIDR-based heuristic to whitelist processors known to support it.
|
* Use a MIDR-based heuristic to whitelist processors known to
|
||||||
|
* support it:
|
||||||
|
* - Processors with Cortex-A76 cores
|
||||||
|
* - Processors with Cortex-A77 cores
|
||||||
|
* - Processors with Cortex-A78 cores
|
||||||
|
* - Processors with Cortex-A510 cores
|
||||||
|
* - Processors with Cortex-A710 cores
|
||||||
|
* - Processors with Cortex-A715 cores
|
||||||
|
* - Processors with Cortex-X1 cores
|
||||||
|
* - Processors with Cortex-X2 cores
|
||||||
|
* - Processors with Cortex-X3 cores
|
||||||
|
* - Processors with Exynos M4 cores
|
||||||
|
* - Processors with Exynos M5 cores
|
||||||
|
* - Neoverse N1 cores
|
||||||
|
* - Neoverse N2 cores
|
||||||
|
* - Neoverse V1 cores
|
||||||
|
* - Neoverse V2 cores
|
||||||
*/
|
*/
|
||||||
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
|
if (chipset->series == cpuinfo_arm_chipset_series_spreadtrum_sc && chipset->model == 9863) {
|
||||||
case UINT32_C(0x4100D0B0): /* Cortex-A76 */
|
cpuinfo_log_warning(
|
||||||
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
|
"VDOT instructions disabled: cause occasional SIGILL on Spreadtrum SC9863A");
|
||||||
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
|
} else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_t && chipset->model == 310) {
|
||||||
case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
|
cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc T310");
|
||||||
case UINT32_C(0x51008040): /* Kryo 485 Gold (Cortex-A76) */
|
} else if (chipset->series == cpuinfo_arm_chipset_series_unisoc_ums && chipset->model == 312) {
|
||||||
case UINT32_C(0x51008050): /* Kryo 485 Silver (Cortex-A55) */
|
cpuinfo_log_warning("VDOT instructions disabled: cause occasional SIGILL on Unisoc UMS312");
|
||||||
case UINT32_C(0x53000030): /* Exynos-M4 */
|
} else {
|
||||||
case UINT32_C(0x53000040): /* Exynos-M5 */
|
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
|
||||||
isa->dot = true;
|
case UINT32_C(0x4100D0B0): /* Cortex-A76 */
|
||||||
break;
|
case UINT32_C(0x4100D0C0): /* Neoverse N1 */
|
||||||
case UINT32_C(0x4100D050): /* Cortex A55: revision 1 or later only */
|
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
|
||||||
isa->dot = !!(midr_get_variant(midr) >= 1);
|
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
|
||||||
break;
|
case UINT32_C(0x4100D400): /* Neoverse V1 */
|
||||||
case UINT32_C(0x4100D0A0): /* Cortex A75: revision 2 or later only */
|
case UINT32_C(0x4100D410): /* Cortex-A78 */
|
||||||
isa->dot = !!(midr_get_variant(midr) >= 2);
|
case UINT32_C(0x4100D440): /* Cortex-X1 */
|
||||||
break;
|
case UINT32_C(0x4100D460): /* Cortex-A510 */
|
||||||
|
case UINT32_C(0x4100D470): /* Cortex-A710 */
|
||||||
|
case UINT32_C(0x4100D480): /* Cortex-X2 */
|
||||||
|
case UINT32_C(0x4100D490): /* Neoverse N2 */
|
||||||
|
case UINT32_C(0x4100D4D0): /* Cortex-A715 */
|
||||||
|
case UINT32_C(0x4100D4E0): /* Cortex-X3 */
|
||||||
|
case UINT32_C(0x4100D4F0): /* Neoverse V2 */
|
||||||
|
case UINT32_C(0x4800D400): /* Cortex-A76
|
||||||
|
(HiSilicon) */
|
||||||
|
case UINT32_C(0x51008040): /* Kryo 485 Gold
|
||||||
|
(Cortex-A76) */
|
||||||
|
case UINT32_C(0x51008050): /* Kryo 485 Silver
|
||||||
|
(Cortex-A55) */
|
||||||
|
case UINT32_C(0x53000030): /* Exynos M4 */
|
||||||
|
case UINT32_C(0x53000040): /* Exynos M5 */
|
||||||
|
isa->dot = true;
|
||||||
|
break;
|
||||||
|
case UINT32_C(0x4100D050): /* Cortex A55: revision 1
|
||||||
|
or later only */
|
||||||
|
isa->dot = !!(midr_get_variant(midr) >= 1);
|
||||||
|
break;
|
||||||
|
case UINT32_C(0x4100D0A0): /* Cortex A75: revision 2
|
||||||
|
or later only */
|
||||||
|
isa->dot = !!(midr_get_variant(midr) >= 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* ARMv7 or lower: use feature flags to detect optional features */
|
/* ARMv7 or lower: use feature flags to detect optional features
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ARM11 (ARM 1136/1156/1176/11 MPCore) processors can report v7 architecture
|
* ARM11 (ARM 1136/1156/1176/11 MPCore) processors can report v7
|
||||||
* even though they support only ARMv6 instruction set.
|
* architecture even though they support only ARMv6 instruction
|
||||||
|
* set.
|
||||||
*/
|
*/
|
||||||
if (architecture_version == 7 && midr_is_arm11(midr)) {
|
if (architecture_version == 7 && midr_is_arm11(midr)) {
|
||||||
cpuinfo_log_warning("kernel-reported architecture ARMv7 ignored due to mismatch with processor microarchitecture (ARM11)");
|
cpuinfo_log_warning(
|
||||||
|
"kernel-reported architecture ARMv7 ignored due to mismatch with processor microarchitecture (ARM11)");
|
||||||
architecture_version = 6;
|
architecture_version = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (architecture_version < 7) {
|
if (architecture_version < 7) {
|
||||||
const uint32_t armv7_features_mask = CPUINFO_ARM_LINUX_FEATURE_VFPV3 | CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | CPUINFO_ARM_LINUX_FEATURE_VFPD32 |
|
const uint32_t armv7_features_mask = CPUINFO_ARM_LINUX_FEATURE_VFPV3 |
|
||||||
CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON | CPUINFO_ARM_LINUX_FEATURE_IDIVT | CPUINFO_ARM_LINUX_FEATURE_IDIVA;
|
CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | CPUINFO_ARM_LINUX_FEATURE_VFPD32 |
|
||||||
|
CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON |
|
||||||
|
CPUINFO_ARM_LINUX_FEATURE_IDIVT | CPUINFO_ARM_LINUX_FEATURE_IDIVA;
|
||||||
if (features & armv7_features_mask) {
|
if (features & armv7_features_mask) {
|
||||||
architecture_version = 7;
|
architecture_version = 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((architecture_version >= 6) || (features & CPUINFO_ARM_LINUX_FEATURE_EDSP) || (architecture_flags & CPUINFO_ARM_LINUX_ARCH_E)) {
|
if ((architecture_version >= 6) || (features & CPUINFO_ARM_LINUX_FEATURE_EDSP) ||
|
||||||
|
(architecture_flags & CPUINFO_ARM_LINUX_ARCH_E)) {
|
||||||
isa->armv5e = true;
|
isa->armv5e = true;
|
||||||
}
|
}
|
||||||
if (architecture_version >= 6) {
|
if (architecture_version >= 6) {
|
||||||
|
@ -141,13 +221,16 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
||||||
isa->armv7 = true;
|
isa->armv7 = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ARMv7 MP extension (PLDW instruction) is not indicated in /proc/cpuinfo.
|
* ARMv7 MP extension (PLDW instruction) is not
|
||||||
* Use heuristic list of supporting processors:
|
* indicated in /proc/cpuinfo. Use heuristic list of
|
||||||
* - Processors supporting UDIV/SDIV instructions ("idiva" + "idivt" features in /proc/cpuinfo)
|
* supporting processors:
|
||||||
|
* - Processors supporting UDIV/SDIV instructions
|
||||||
|
* ("idiva" + "idivt" features in /proc/cpuinfo)
|
||||||
* - Cortex-A5
|
* - Cortex-A5
|
||||||
* - Cortex-A9
|
* - Cortex-A9
|
||||||
* - Dual-Core Scorpion
|
* - Dual-Core Scorpion
|
||||||
* - Krait (supports UDIV/SDIV, but kernels may not report it in /proc/cpuinfo)
|
* - Krait (supports UDIV/SDIV, but kernels may not
|
||||||
|
* report it in /proc/cpuinfo)
|
||||||
*
|
*
|
||||||
* TODO: check single-core Qualcomm Scorpion.
|
* TODO: check single-core Qualcomm Scorpion.
|
||||||
*/
|
*/
|
||||||
|
@ -160,15 +243,18 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
||||||
isa->armv7mp = true;
|
isa->armv7mp = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* In practice IDIV instruction implies ARMv7+MP ISA */
|
/* In practice IDIV instruction implies
|
||||||
isa->armv7mp = (features & CPUINFO_ARM_LINUX_FEATURE_IDIV) == CPUINFO_ARM_LINUX_FEATURE_IDIV;
|
* ARMv7+MP ISA */
|
||||||
|
isa->armv7mp = (features & CPUINFO_ARM_LINUX_FEATURE_IDIV) ==
|
||||||
|
CPUINFO_ARM_LINUX_FEATURE_IDIV;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (features & CPUINFO_ARM_LINUX_FEATURE_IWMMXT) {
|
if (features & CPUINFO_ARM_LINUX_FEATURE_IWMMXT) {
|
||||||
|
#if !defined(__ARM_ARCH_8A__) && !(defined(__ARM_ARCH) && (__ARM_ARCH >= 8))
|
||||||
const uint32_t wcid = read_wcid();
|
const uint32_t wcid = read_wcid();
|
||||||
cpuinfo_log_debug("WCID = 0x%08"PRIx32, wcid);
|
cpuinfo_log_debug("WCID = 0x%08" PRIx32, wcid);
|
||||||
const uint32_t coprocessor_type = (wcid >> 8) & UINT32_C(0xFF);
|
const uint32_t coprocessor_type = (wcid >> 8) & UINT32_C(0xFF);
|
||||||
if (coprocessor_type >= 0x10) {
|
if (coprocessor_type >= 0x10) {
|
||||||
isa->wmmx = true;
|
isa->wmmx = true;
|
||||||
|
@ -176,10 +262,16 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
||||||
isa->wmmx2 = true;
|
isa->wmmx2 = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cpuinfo_log_warning("WMMX ISA disabled: OS reported iwmmxt feature, "
|
cpuinfo_log_warning(
|
||||||
"but WCID coprocessor type 0x%"PRIx32" indicates no WMMX support",
|
"WMMX ISA disabled: OS reported iwmmxt feature, "
|
||||||
|
"but WCID coprocessor type 0x%" PRIx32 " indicates no WMMX support",
|
||||||
coprocessor_type);
|
coprocessor_type);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
cpuinfo_log_warning(
|
||||||
|
"WMMX ISA disabled: OS reported iwmmxt feature, "
|
||||||
|
"but there is no iWMMXt coprocessor");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((features & CPUINFO_ARM_LINUX_FEATURE_THUMB) || (architecture_flags & CPUINFO_ARM_LINUX_ARCH_T)) {
|
if ((features & CPUINFO_ARM_LINUX_FEATURE_THUMB) || (architecture_flags & CPUINFO_ARM_LINUX_ARCH_T)) {
|
||||||
|
@ -200,35 +292,39 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
||||||
isa->jazelle = true;
|
isa->jazelle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Qualcomm Krait may have buggy kernel configuration that doesn't report IDIV */
|
/* Qualcomm Krait may have buggy kernel configuration that
|
||||||
if ((features & CPUINFO_ARM_LINUX_FEATURE_IDIV) == CPUINFO_ARM_LINUX_FEATURE_IDIV || midr_is_krait(midr)) {
|
* doesn't report IDIV */
|
||||||
|
if ((features & CPUINFO_ARM_LINUX_FEATURE_IDIV) == CPUINFO_ARM_LINUX_FEATURE_IDIV ||
|
||||||
|
midr_is_krait(midr)) {
|
||||||
isa->idiv = true;
|
isa->idiv = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t vfp_mask = \
|
const uint32_t vfp_mask = CPUINFO_ARM_LINUX_FEATURE_VFP | CPUINFO_ARM_LINUX_FEATURE_VFPV3 |
|
||||||
CPUINFO_ARM_LINUX_FEATURE_VFP | CPUINFO_ARM_LINUX_FEATURE_VFPV3 | CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | \
|
CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | CPUINFO_ARM_LINUX_FEATURE_VFPD32 |
|
||||||
CPUINFO_ARM_LINUX_FEATURE_VFPD32 | CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON;
|
CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON;
|
||||||
if (features & vfp_mask) {
|
if (features & vfp_mask) {
|
||||||
const uint32_t vfpv3_mask = CPUINFO_ARM_LINUX_FEATURE_VFPV3 | CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | \
|
const uint32_t vfpv3_mask = CPUINFO_ARM_LINUX_FEATURE_VFPV3 |
|
||||||
CPUINFO_ARM_LINUX_FEATURE_VFPD32 | CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON;
|
CPUINFO_ARM_LINUX_FEATURE_VFPV3D16 | CPUINFO_ARM_LINUX_FEATURE_VFPD32 |
|
||||||
|
CPUINFO_ARM_LINUX_FEATURE_VFPV4 | CPUINFO_ARM_LINUX_FEATURE_NEON;
|
||||||
if ((architecture_version >= 7) || (features & vfpv3_mask)) {
|
if ((architecture_version >= 7) || (features & vfpv3_mask)) {
|
||||||
isa->vfpv3 = true;
|
isa->vfpv3 = true;
|
||||||
|
|
||||||
const uint32_t d32_mask = CPUINFO_ARM_LINUX_FEATURE_VFPD32 | CPUINFO_ARM_LINUX_FEATURE_NEON;
|
const uint32_t d32_mask =
|
||||||
|
CPUINFO_ARM_LINUX_FEATURE_VFPD32 | CPUINFO_ARM_LINUX_FEATURE_NEON;
|
||||||
if (features & d32_mask) {
|
if (features & d32_mask) {
|
||||||
isa->d32 = true;
|
isa->d32 = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
|
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
|
||||||
isa->vfpv3 = true;
|
isa->vfpv3 = true;
|
||||||
#else
|
#else
|
||||||
const uint32_t fpsid = read_fpsid();
|
const uint32_t fpsid = read_fpsid();
|
||||||
cpuinfo_log_debug("FPSID = 0x%08"PRIx32, fpsid);
|
cpuinfo_log_debug("FPSID = 0x%08" PRIx32, fpsid);
|
||||||
const uint32_t subarchitecture = (fpsid >> 16) & UINT32_C(0x7F);
|
const uint32_t subarchitecture = (fpsid >> 16) & UINT32_C(0x7F);
|
||||||
if (subarchitecture >= 0x01) {
|
if (subarchitecture >= 0x01) {
|
||||||
isa->vfpv2 = true;
|
isa->vfpv2 = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (features & CPUINFO_ARM_LINUX_FEATURE_NEON) {
|
if (features & CPUINFO_ARM_LINUX_FEATURE_NEON) {
|
||||||
|
@ -237,8 +333,9 @@ void cpuinfo_arm_linux_decode_isa_from_proc_cpuinfo(
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There is no separate feature flag for FP16 support.
|
* There is no separate feature flag for FP16 support.
|
||||||
* VFPv4 implies VFPv3-FP16 support (and in practice, NEON-HP as well).
|
* VFPv4 implies VFPv3-FP16 support (and in practice, NEON-HP as
|
||||||
* Additionally, ARM Cortex-A9 and Qualcomm Scorpion support FP16.
|
* well). Additionally, ARM Cortex-A9 and Qualcomm Scorpion
|
||||||
|
* support FP16.
|
||||||
*/
|
*/
|
||||||
if ((features & CPUINFO_ARM_LINUX_FEATURE_VFPV4) || midr_is_cortex_a9(midr) || midr_is_scorpion(midr)) {
|
if ((features & CPUINFO_ARM_LINUX_FEATURE_VFPV4) || midr_is_cortex_a9(midr) || midr_is_scorpion(midr)) {
|
||||||
isa->fp16 = true;
|
isa->fp16 = true;
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
#include <arm/linux/api.h>
|
#include <arm/linux/api.h>
|
||||||
#include <cpuinfo/log.h>
|
#include <cpuinfo/log.h>
|
||||||
|
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
|
void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
|
||||||
uint32_t features,
|
uint32_t features,
|
||||||
uint32_t features2,
|
uint64_t features2,
|
||||||
uint32_t midr,
|
uint32_t midr,
|
||||||
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
const struct cpuinfo_arm_chipset chipset[restrict static 1],
|
||||||
struct cpuinfo_arm_isa isa[restrict static 1])
|
struct cpuinfo_arm_isa isa[restrict static 1]) {
|
||||||
{
|
|
||||||
if (features & CPUINFO_ARM_LINUX_FEATURE_AES) {
|
if (features & CPUINFO_ARM_LINUX_FEATURE_AES) {
|
||||||
isa->aes = true;
|
isa->aes = true;
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,10 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some phones ship with an old kernel configuration that doesn't report NEON FP16 compute extension and SQRDMLAH/SQRDMLSH/UQRDMLAH/UQRDMLSH instructions.
|
* Some phones ship with an old kernel configuration that doesn't report
|
||||||
* Use a MIDR-based heuristic to whitelist processors known to support it:
|
* NEON FP16 compute extension and SQRDMLAH/SQRDMLSH/UQRDMLAH/UQRDMLSH
|
||||||
|
* instructions. Use a MIDR-based heuristic to whitelist processors
|
||||||
|
* known to support it:
|
||||||
* - Processors with Cortex-A55 cores
|
* - Processors with Cortex-A55 cores
|
||||||
* - Processors with Cortex-A65 cores
|
* - Processors with Cortex-A65 cores
|
||||||
* - Processors with Cortex-A75 cores
|
* - Processors with Cortex-A75 cores
|
||||||
|
@ -41,19 +43,28 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
|
||||||
* - Processors with Exynos M4 cores
|
* - Processors with Exynos M4 cores
|
||||||
* - Processors with Exynos M5 cores
|
* - Processors with Exynos M5 cores
|
||||||
* - Neoverse N1 cores
|
* - Neoverse N1 cores
|
||||||
|
* - Neoverse V1 cores
|
||||||
|
* - Neoverse N2 cores
|
||||||
|
* - Neoverse V2 cores
|
||||||
*/
|
*/
|
||||||
if (chipset->series == cpuinfo_arm_chipset_series_samsung_exynos && chipset->model == 9810) {
|
if (chipset->series == cpuinfo_arm_chipset_series_samsung_exynos && chipset->model == 9810) {
|
||||||
/* Exynos 9810 reports that it supports FP16 compute, but in fact only little cores do */
|
/* Exynos 9810 reports that it supports FP16 compute, but in
|
||||||
cpuinfo_log_warning("FP16 arithmetics and RDM disabled: only little cores in Exynos 9810 support these extensions");
|
* fact only little cores do */
|
||||||
|
cpuinfo_log_warning(
|
||||||
|
"FP16 arithmetics and RDM disabled: only little cores in Exynos 9810 support these extensions");
|
||||||
} else {
|
} else {
|
||||||
const uint32_t fp16arith_mask = CPUINFO_ARM_LINUX_FEATURE_FPHP | CPUINFO_ARM_LINUX_FEATURE_ASIMDHP;
|
const uint32_t fp16arith_mask = CPUINFO_ARM_LINUX_FEATURE_FPHP | CPUINFO_ARM_LINUX_FEATURE_ASIMDHP;
|
||||||
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
|
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
|
||||||
case UINT32_C(0x4100D050): /* Cortex-A55 */
|
case UINT32_C(0x4100D050): /* Cortex-A55 */
|
||||||
case UINT32_C(0x4100D060): /* Cortex-A65 */
|
case UINT32_C(0x4100D060): /* Cortex-A65 */
|
||||||
|
case UINT32_C(0x4100D0A0): /* Cortex-A75 */
|
||||||
case UINT32_C(0x4100D0B0): /* Cortex-A76 */
|
case UINT32_C(0x4100D0B0): /* Cortex-A76 */
|
||||||
case UINT32_C(0x4100D0C0): /* Neoverse N1 */
|
case UINT32_C(0x4100D0C0): /* Neoverse N1 */
|
||||||
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
|
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
|
||||||
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
|
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
|
||||||
|
case UINT32_C(0x4100D400): /* Neoverse V1 */
|
||||||
|
case UINT32_C(0x4100D490): /* Neoverse N2 */
|
||||||
|
case UINT32_C(0x4100D4F0): /* Neoverse V2 */
|
||||||
case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
|
case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
|
||||||
case UINT32_C(0x51008020): /* Kryo 385 Gold (Cortex-A75) */
|
case UINT32_C(0x51008020): /* Kryo 385 Gold (Cortex-A75) */
|
||||||
case UINT32_C(0x51008030): /* Kryo 385 Silver (Cortex-A55) */
|
case UINT32_C(0x51008030): /* Kryo 385 Silver (Cortex-A55) */
|
||||||
|
@ -68,9 +79,11 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
|
||||||
if ((features & fp16arith_mask) == fp16arith_mask) {
|
if ((features & fp16arith_mask) == fp16arith_mask) {
|
||||||
isa->fp16arith = true;
|
isa->fp16arith = true;
|
||||||
} else if (features & CPUINFO_ARM_LINUX_FEATURE_FPHP) {
|
} else if (features & CPUINFO_ARM_LINUX_FEATURE_FPHP) {
|
||||||
cpuinfo_log_warning("FP16 arithmetics disabled: detected support only for scalar operations");
|
cpuinfo_log_warning(
|
||||||
|
"FP16 arithmetics disabled: detected support only for scalar operations");
|
||||||
} else if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDHP) {
|
} else if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDHP) {
|
||||||
cpuinfo_log_warning("FP16 arithmetics disabled: detected support only for SIMD operations");
|
cpuinfo_log_warning(
|
||||||
|
"FP16 arithmetics disabled: detected support only for SIMD operations");
|
||||||
}
|
}
|
||||||
if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDRDM) {
|
if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDRDM) {
|
||||||
isa->rdm = true;
|
isa->rdm = true;
|
||||||
|
@ -78,10 +91,14 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_I8MM) {
|
||||||
|
isa->i8mm = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Many phones ship with an old kernel configuration that doesn't report UDOT/SDOT instructions.
|
* Many phones ship with an old kernel configuration that doesn't report
|
||||||
* Use a MIDR-based heuristic to whitelist processors known to support it.
|
* UDOT/SDOT instructions. Use a MIDR-based heuristic to whitelist
|
||||||
|
* processors known to support it.
|
||||||
*/
|
*/
|
||||||
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
|
switch (midr & (CPUINFO_ARM_MIDR_IMPLEMENTER_MASK | CPUINFO_ARM_MIDR_PART_MASK)) {
|
||||||
case UINT32_C(0x4100D060): /* Cortex-A65 */
|
case UINT32_C(0x4100D060): /* Cortex-A65 */
|
||||||
|
@ -89,7 +106,10 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
|
||||||
case UINT32_C(0x4100D0C0): /* Neoverse N1 */
|
case UINT32_C(0x4100D0C0): /* Neoverse N1 */
|
||||||
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
|
case UINT32_C(0x4100D0D0): /* Cortex-A77 */
|
||||||
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
|
case UINT32_C(0x4100D0E0): /* Cortex-A76AE */
|
||||||
|
case UINT32_C(0x4100D400): /* Neoverse V1 */
|
||||||
|
case UINT32_C(0x4100D490): /* Neoverse N2 */
|
||||||
case UINT32_C(0x4100D4A0): /* Neoverse E1 */
|
case UINT32_C(0x4100D4A0): /* Neoverse E1 */
|
||||||
|
case UINT32_C(0x4100D4F0): /* Neoverse V2 */
|
||||||
case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
|
case UINT32_C(0x4800D400): /* Cortex-A76 (HiSilicon) */
|
||||||
case UINT32_C(0x51008040): /* Kryo 485 Gold (Cortex-A76) */
|
case UINT32_C(0x51008040): /* Kryo 485 Gold (Cortex-A76) */
|
||||||
case UINT32_C(0x51008050): /* Kryo 485 Silver (Cortex-A55) */
|
case UINT32_C(0x51008050): /* Kryo 485 Silver (Cortex-A55) */
|
||||||
|
@ -124,4 +144,51 @@ void cpuinfo_arm64_linux_decode_isa_from_proc_cpuinfo(
|
||||||
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SVE2) {
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SVE2) {
|
||||||
isa->sve2 = true;
|
isa->sve2 = true;
|
||||||
}
|
}
|
||||||
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME) {
|
||||||
|
isa->sme = true;
|
||||||
|
}
|
||||||
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME2) {
|
||||||
|
isa->sme2 = true;
|
||||||
|
}
|
||||||
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME2P1) {
|
||||||
|
isa->sme2p1 = true;
|
||||||
|
}
|
||||||
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_I16I32) {
|
||||||
|
isa->sme_i16i32 = true;
|
||||||
|
}
|
||||||
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_BI32I32) {
|
||||||
|
isa->sme_bi32i32 = true;
|
||||||
|
}
|
||||||
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_B16B16) {
|
||||||
|
isa->sme_b16b16 = true;
|
||||||
|
}
|
||||||
|
if (features2 & CPUINFO_ARM_LINUX_FEATURE2_SME_F16F16) {
|
||||||
|
isa->sme_f16f16 = true;
|
||||||
|
}
|
||||||
|
// SVEBF16 is set iff SVE and BF16 are both supported, but the SVEBF16
|
||||||
|
// feature flag was added in Linux kernel before the BF16 feature flag,
|
||||||
|
// so we check for either.
|
||||||
|
if (features2 & (CPUINFO_ARM_LINUX_FEATURE2_BF16 | CPUINFO_ARM_LINUX_FEATURE2_SVEBF16)) {
|
||||||
|
isa->bf16 = true;
|
||||||
|
}
|
||||||
|
if (features & CPUINFO_ARM_LINUX_FEATURE_ASIMDFHM) {
|
||||||
|
isa->fhm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PR_SVE_GET_VL
|
||||||
|
#define PR_SVE_GET_VL 51
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PR_SVE_VL_LEN_MASK
|
||||||
|
#define PR_SVE_VL_LEN_MASK 0xffff
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ret = prctl(PR_SVE_GET_VL);
|
||||||
|
if (ret < 0) {
|
||||||
|
cpuinfo_log_warning("No SVE support on this machine");
|
||||||
|
isa->svelen = 0; // Assume no SVE support if the call fails
|
||||||
|
} else {
|
||||||
|
// Mask out the SVE vector length bits
|
||||||
|
isa->svelen = ret & PR_SVE_VL_LEN_MASK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue