diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index fe04761d..e75c3362 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -8,15 +8,71 @@ on:
jobs:
dotnet-job:
name: ".NET"
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.platform.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ platform:
+ - { name: Windows x64 (mingw64), os: windows-latest, shell: 'msys2 {0}', msystem: mingw64, msys-env: mingw-w64-x86_64 }
+ - { name: Windows x64, os: windows-latest, shell: bash }
+ # Using Ubuntu 18.04 because of GitHub Actions Runner bug: https://github.com/actions/runner/issues/1819#issuecomment-1098641309
+ - { name: Linux x64, os: ubuntu-18.04, shell: bash }
+ - { name: macOS x64, os: macos-latest, shell: bash }
+ defaults:
+ run:
+ shell: ${{ matrix.platform.shell }}
steps:
- - uses: bottlenoselabs/github-actions-dotnet@v2
- with:
- repository: '${{ github.repository }}'
- dotnet-sdk-version: '6.0.x'
- is-enabled-pack: 'true'
- upload-myget-org: "${{ github.event_name == 'push' || startsWith(github.ref, 'refs/tags/v') }}"
- upload-nuget-org: "${{ startsWith(github.ref, 'refs/tags/v') }}"
- myget-access-token: '${{ secrets.MYGET_ACCESS_TOKEN }}'
- nuget-access-token: '${{ secrets.NUGET_ACCESS_TOKEN }}'
+
+ - name: "Set up MSYS2"
+ if: matrix.platform.shell == 'msys2 {0}'
+ uses: msys2/setup-msys2@v2
+ with:
+ msystem: ${{ matrix.platform.msystem }}
+ install: >-
+ ${{ matrix.platform.msys-env }}-gcc
+ ${{ matrix.platform.msys-env }}-cmake
+ ${{ matrix.platform.msys-env }}-ninja
+ ${{ matrix.platform.msys-env }}-pkg-config
+ unzip
+
+ - name: "Clone Git repository"
+ uses: actions/checkout@v1
+ with:
+ fetch-depth: 0
+ submodules: 'recursive'
+
+ - name: "Install Clang: Windows"
+ if: matrix.platform.os == 'windows-latest'
+ run: |
+ source "${{ github.workspace }}\scripts\install-clang-x64-windows.sh"
+
+ - name: "Install Clang: Linux"
+ if: matrix.platform.os == 'ubuntu-18.04'
+ run: |
+ sudo apt-get update
+ sudo apt-get install gcc-multilib
+ source "${{ github.workspace }}/scripts/install-clang-x64-ubuntu_18_04.sh"
+
+ - name: "Install Clang: macOS"
+ if: matrix.platform.os == 'macos-latest'
+ run: |
+ source "${{ github.workspace }}/scripts/install-clang-macos.sh"
+
+ - name: ".NET"
+ uses: bottlenoselabs/github-actions-dotnet@v3
+ with:
+ dotnet-sdk-version: "6.0.x"
+ solution-or-project: "${{ github.workspace }}/C2CS.sln"
+ is-enabled-upload-myget: "${{ matrix.platform.os == 'ubuntu-18.04' && ( github.event_name == 'push' || startsWith(github.ref, 'refs/tags/v') ) }}"
+ is-enabled-upload-nuget: "${{ matrix.platform.os == 'ubuntu-18.04' && startsWith(github.ref, 'refs/tags/v') }}"
+ myget-access-token: "${{ secrets.MYGET_ACCESS_TOKEN }}"
+ nuget-access-token: "${{ secrets.NUGET_ACCESS_TOKEN }}"
+
+ - uses: actions/upload-artifact@v3
+ if: ${{ failure() }}
+ with:
+ name: "Failing Test Data ${{ matrix.platform.name }}"
+ path: |
+ ${{ github.workspace }}/bin/*Tests*/**/*.cs
+ ${{ github.workspace }}/bin/*Tests*/**/ast/*.json
diff --git a/C2CS.sln b/C2CS.sln
index fe24a810..f6bca9d6 100644
--- a/C2CS.sln
+++ b/C2CS.sln
@@ -10,21 +10,29 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "helloworld-c", "src\cs\exam
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "helloworld-cs", "src\cs\examples\helloworld\helloworld-cs\helloworld-cs.csproj", "{3549CD6F-971A-4456-8F80-EFC826AECC04}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "clang-cs", "src\cs\production\clang-cs\clang-cs.csproj", "{D22C766F-7E8B-4E81-899E-6CA1E624779B}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS", "src\cs\production\C2CS\C2CS.csproj", "{2E53A130-519C-4C5F-8D76-86CEA17A160F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "clang-c", "src\cs\production\clang-c\clang-c.csproj", "{2CF10B9A-7845-4DB7-9B02-75D62A4DABA4}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{995D2D9A-AAF6-4034-8625-5BB812C2870F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS", "src\cs\production\C2CS\C2CS.csproj", "{2E53A130-519C-4C5F-8D76-86CEA17A160F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Tests.Integration", "src\cs\tests\C2CS.Tests.Integration\C2CS.Tests.Integration.csproj", "{3C179AE6-E9B5-4B89-B441-863FF393CC85}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "features", "features", "{FF3312B1-10D2-4B8A-AD43-3F6D9CE5E61F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Feature.ReadCodeC", "src\cs\production\features\C2CS.Feature.ReadCodeC\C2CS.Feature.ReadCodeC.csproj", "{EB040AE8-5CF1-4A79-9881-2B5CAED4D224}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Feature.BuildLibraryC", "src\cs\production\features\C2CS.Feature.BuildLibraryC\C2CS.Feature.BuildLibraryC.csproj", "{00E6F00B-FF25-40AA-BE41-5A736FA1541C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Feature.WriteCodeCSharp", "src\cs\production\features\C2CS.Feature.WriteCodeCSharp\C2CS.Feature.WriteCodeCSharp.csproj", "{56251683-F977-4AFC-A51D-733F9D022A61}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Runtime", "src\cs\production\C2CS.Runtime\C2CS.Runtime.csproj", "{16C004F6-755D-4976-9EEB-A61BE1223AF2}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "infrastructure", "infrastructure", "{3F11D389-67E8-40D9-B235-224F27F7BFC8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Common", "src\cs\production\C2CS.Common\C2CS.Common.csproj", "{2B7BFB9A-E304-4855-ABEF-A4F426BC78F3}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "clang-cs", "src\cs\production\infrastructure\clang-cs\clang-cs.csproj", "{BEE5DEBA-4A80-47FC-9C0C-80F136EBBA71}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Feature.BuildLibraryC", "src\cs\production\C2CS.Feature.BuildLibraryC\C2CS.Feature.BuildLibraryC.csproj", "{9BA29F5A-ECF9-41E3-944C-28B7D837D50B}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "clang-c", "src\cs\production\infrastructure\clang-c\clang-c.csproj", "{E206B026-28AB-41D9-8B44-A3EC8A216FA3}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Feature.ExtractAbstractSyntaxTreeC", "src\cs\production\C2CS.Feature.ExtractAbstractSyntaxTreeC\C2CS.Feature.ExtractAbstractSyntaxTreeC.csproj", "{1D574489-0CE2-4BAC-AA53-92AA69FB69FD}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Runtime", "src\cs\production\infrastructure\C2CS.Runtime\C2CS.Runtime.csproj", "{C3ACC4B9-2573-4171-BA52-959725A74D25}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Feature.BindgenCSharp", "src\cs\production\C2CS.Feature.BindgenCSharp\C2CS.Feature.BindgenCSharp.csproj", "{A126534B-01B0-477B-9DDB-43BA54D09CA1}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Common", "src\cs\production\infrastructure\C2CS.Common\C2CS.Common.csproj", "{9500EF1F-4F03-4D02-99E6-5140C806EB0C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -40,50 +48,57 @@ Global
{3549CD6F-971A-4456-8F80-EFC826AECC04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3549CD6F-971A-4456-8F80-EFC826AECC04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3549CD6F-971A-4456-8F80-EFC826AECC04}.Release|Any CPU.Build.0 = Release|Any CPU
- {D22C766F-7E8B-4E81-899E-6CA1E624779B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D22C766F-7E8B-4E81-899E-6CA1E624779B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D22C766F-7E8B-4E81-899E-6CA1E624779B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D22C766F-7E8B-4E81-899E-6CA1E624779B}.Release|Any CPU.Build.0 = Release|Any CPU
- {2CF10B9A-7845-4DB7-9B02-75D62A4DABA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2CF10B9A-7845-4DB7-9B02-75D62A4DABA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2CF10B9A-7845-4DB7-9B02-75D62A4DABA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2CF10B9A-7845-4DB7-9B02-75D62A4DABA4}.Release|Any CPU.Build.0 = Release|Any CPU
{2E53A130-519C-4C5F-8D76-86CEA17A160F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E53A130-519C-4C5F-8D76-86CEA17A160F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E53A130-519C-4C5F-8D76-86CEA17A160F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E53A130-519C-4C5F-8D76-86CEA17A160F}.Release|Any CPU.Build.0 = Release|Any CPU
- {16C004F6-755D-4976-9EEB-A61BE1223AF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {16C004F6-755D-4976-9EEB-A61BE1223AF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {16C004F6-755D-4976-9EEB-A61BE1223AF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {16C004F6-755D-4976-9EEB-A61BE1223AF2}.Release|Any CPU.Build.0 = Release|Any CPU
- {2B7BFB9A-E304-4855-ABEF-A4F426BC78F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2B7BFB9A-E304-4855-ABEF-A4F426BC78F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2B7BFB9A-E304-4855-ABEF-A4F426BC78F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2B7BFB9A-E304-4855-ABEF-A4F426BC78F3}.Release|Any CPU.Build.0 = Release|Any CPU
- {9BA29F5A-ECF9-41E3-944C-28B7D837D50B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9BA29F5A-ECF9-41E3-944C-28B7D837D50B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9BA29F5A-ECF9-41E3-944C-28B7D837D50B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9BA29F5A-ECF9-41E3-944C-28B7D837D50B}.Release|Any CPU.Build.0 = Release|Any CPU
- {1D574489-0CE2-4BAC-AA53-92AA69FB69FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1D574489-0CE2-4BAC-AA53-92AA69FB69FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1D574489-0CE2-4BAC-AA53-92AA69FB69FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1D574489-0CE2-4BAC-AA53-92AA69FB69FD}.Release|Any CPU.Build.0 = Release|Any CPU
- {A126534B-01B0-477B-9DDB-43BA54D09CA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A126534B-01B0-477B-9DDB-43BA54D09CA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A126534B-01B0-477B-9DDB-43BA54D09CA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A126534B-01B0-477B-9DDB-43BA54D09CA1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3C179AE6-E9B5-4B89-B441-863FF393CC85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3C179AE6-E9B5-4B89-B441-863FF393CC85}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3C179AE6-E9B5-4B89-B441-863FF393CC85}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3C179AE6-E9B5-4B89-B441-863FF393CC85}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EB040AE8-5CF1-4A79-9881-2B5CAED4D224}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EB040AE8-5CF1-4A79-9881-2B5CAED4D224}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EB040AE8-5CF1-4A79-9881-2B5CAED4D224}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EB040AE8-5CF1-4A79-9881-2B5CAED4D224}.Release|Any CPU.Build.0 = Release|Any CPU
+ {00E6F00B-FF25-40AA-BE41-5A736FA1541C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {00E6F00B-FF25-40AA-BE41-5A736FA1541C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {00E6F00B-FF25-40AA-BE41-5A736FA1541C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {00E6F00B-FF25-40AA-BE41-5A736FA1541C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {56251683-F977-4AFC-A51D-733F9D022A61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {56251683-F977-4AFC-A51D-733F9D022A61}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {56251683-F977-4AFC-A51D-733F9D022A61}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {56251683-F977-4AFC-A51D-733F9D022A61}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BEE5DEBA-4A80-47FC-9C0C-80F136EBBA71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BEE5DEBA-4A80-47FC-9C0C-80F136EBBA71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BEE5DEBA-4A80-47FC-9C0C-80F136EBBA71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BEE5DEBA-4A80-47FC-9C0C-80F136EBBA71}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E206B026-28AB-41D9-8B44-A3EC8A216FA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E206B026-28AB-41D9-8B44-A3EC8A216FA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E206B026-28AB-41D9-8B44-A3EC8A216FA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E206B026-28AB-41D9-8B44-A3EC8A216FA3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C3ACC4B9-2573-4171-BA52-959725A74D25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C3ACC4B9-2573-4171-BA52-959725A74D25}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C3ACC4B9-2573-4171-BA52-959725A74D25}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C3ACC4B9-2573-4171-BA52-959725A74D25}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9500EF1F-4F03-4D02-99E6-5140C806EB0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9500EF1F-4F03-4D02-99E6-5140C806EB0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9500EF1F-4F03-4D02-99E6-5140C806EB0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9500EF1F-4F03-4D02-99E6-5140C806EB0C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{69316361-0268-46E8-ADE6-89102DEB3166} = {E5C474A9-491B-4719-B253-09F93D5CEA5B}
{1DD50076-2E66-4EC4-99AA-D8F2539EF48D} = {69316361-0268-46E8-ADE6-89102DEB3166}
{3549CD6F-971A-4456-8F80-EFC826AECC04} = {69316361-0268-46E8-ADE6-89102DEB3166}
- {D22C766F-7E8B-4E81-899E-6CA1E624779B} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
- {2CF10B9A-7845-4DB7-9B02-75D62A4DABA4} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
{2E53A130-519C-4C5F-8D76-86CEA17A160F} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
- {16C004F6-755D-4976-9EEB-A61BE1223AF2} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
- {2B7BFB9A-E304-4855-ABEF-A4F426BC78F3} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
- {9BA29F5A-ECF9-41E3-944C-28B7D837D50B} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
- {1D574489-0CE2-4BAC-AA53-92AA69FB69FD} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
- {A126534B-01B0-477B-9DDB-43BA54D09CA1} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
+ {3C179AE6-E9B5-4B89-B441-863FF393CC85} = {995D2D9A-AAF6-4034-8625-5BB812C2870F}
+ {FF3312B1-10D2-4B8A-AD43-3F6D9CE5E61F} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
+ {EB040AE8-5CF1-4A79-9881-2B5CAED4D224} = {FF3312B1-10D2-4B8A-AD43-3F6D9CE5E61F}
+ {00E6F00B-FF25-40AA-BE41-5A736FA1541C} = {FF3312B1-10D2-4B8A-AD43-3F6D9CE5E61F}
+ {56251683-F977-4AFC-A51D-733F9D022A61} = {FF3312B1-10D2-4B8A-AD43-3F6D9CE5E61F}
+ {3F11D389-67E8-40D9-B235-224F27F7BFC8} = {0B6FBBF3-28F7-4374-9CDD-3C8B1DFD2AB8}
+ {BEE5DEBA-4A80-47FC-9C0C-80F136EBBA71} = {3F11D389-67E8-40D9-B235-224F27F7BFC8}
+ {E206B026-28AB-41D9-8B44-A3EC8A216FA3} = {3F11D389-67E8-40D9-B235-224F27F7BFC8}
+ {C3ACC4B9-2573-4171-BA52-959725A74D25} = {3F11D389-67E8-40D9-B235-224F27F7BFC8}
+ {9500EF1F-4F03-4D02-99E6-5140C806EB0C} = {3F11D389-67E8-40D9-B235-224F27F7BFC8}
EndGlobalSection
EndGlobal
diff --git a/README.md b/README.md
index 8982a901..21369664 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,7 @@ C to C# library bindings code generator. In go `.h` file, out come `.cs` file.
## Documentation
-For documentation see the [docs/README.md](docs/README.md). This includes:
-
-- [How to install `C2CS`](docs/README.md#install)
-- [How to use `C2CS`](docs/README.md#how-to-use).
-- [How to build `C2CS` and the examples from source](docs/README.md#building-from-source).
-- [Examples](docs/README.md#examples).
+For documentation on how to install, use, or build `C2CS` see the [docs/README.md](docs/README.md).
## Background: Why?
@@ -24,13 +19,15 @@ If you are not familiar already with interoperability of C/C++ with C#, it's ass
### Solution
-Automatically generate the bindings by compiling/parsing a C `.h` file. Essentially, the C public programmer application interface (API, those functions you want to call) is tranpiled to C# for the target application binary interface (ABI, operating- system/architecture combo) for use via platform invoke (P/Invoke).
+Automatically generate the bindings by compiling/parsing a C `.h` file. The C API (application programmer interface; those functions you want to call) is tranpiled to C# for the target ABI (application binary interface; a Clang target triple `arch-vendor-os-environment`, e.g. `x86_64-pc-windows-msvc`) for use via P/Invoke (platform invoke).
-This includes all C extern functions which are transpiled to `static` methods respecitively in C# using `DllImport` attribute. Also includes transpiling all the C types to C# which are found through transitive property to the extern functions such as: `struct`s, `enum`s, and `const`s. C# `struct`s are generated instead of `class`es on purpose to achieve 1-1 bit-representation of C to C# types called *blittable* types. The reason for blittable types is to achieve pass-through marshalling and active avoidance of the Garbage Collector in C# for best possible runtime performance and portability when doing interoperability with C.
+Includes all C extern functions which are transpiled to `static` methods respecitively in C# using `DllImport` attribute. The C types which are found through transitive property to the extern functions such as: `struct`s, `enum`s, and `const`s are also transpiled to C#. C# `struct`s are generated instead of `class`es on purpose to achieve 1-1 bit-representation of C to C# types called *blittable* types. The reason for blittable types is to achieve pass-through marshalling and active avoidance of the Garbage Collector in C# for best possible runtime performance and portability when doing interoperability with C.
This is all accomplished by using [libclang](https://clang.llvm.org/docs/Tooling.html) for parsing C and [Roslyn](https://github.com/dotnet/roslyn) for generating C#. All naming is left as found in the C header `.h` file(s).
-
+
+
+
### Limitations
diff --git a/docs/README.md b/docs/README.md
index 46d69d0a..161364c7 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,12 +1,26 @@
# Documentation
-Here you will find documentation for `C2CS` including:
-
-- [Installing `C2CS`](#installing-c2cs)
-- [How to use `C2CS`](#how-to-use-c2cs).
-- [How to use `C2CS.Runtime`](#how-to-use-c2csruntime).
-- [How to build `C2CS` from source](#building-c2cs-from-source).
-- [Examples](#examples).
+Here you will find documentation for `C2CS`:
+
+- [Documentation](#documentation)
+ - [Installing `C2CS`](#installing-c2cs)
+ - [Latest release](#latest-release)
+ - [Latest pre-release](#latest-pre-release)
+ - [How to use `C2CS`](#how-to-use-c2cs)
+ - [Configuration `.json` properties](#configuration-json-properties)
+ - [Cross-parsing with `C2CS`](#cross-parsing-with-c2cs)
+ - [How to use `C2CS.Runtime`](#how-to-use-c2csruntime)
+ - [Custom C# project properties for `C2CS.Runtime`](#custom-c-project-properties-for-c2csruntime)
+ - [`SIZEOF_WCHAR_T`:](#sizeof_wchar_t)
+ - [Building `C2CS` from source](#building-c2cs-from-source)
+ - [Prerequisites](#prerequisites)
+ - [Visual Studio / Rider / MonoDevelop](#visual-studio--rider--monodevelop)
+ - [Command Line Interface (CLI)](#command-line-interface-cli)
+ - [Debugging `C2CS` from source](#debugging-c2cs-from-source)
+ - [Debugging using logging](#debugging-using-logging)
+ - [Examples](#examples)
+ - [Hello world](#hello-world)
+ - [libclang](#libclang)
## Installing `C2CS`
@@ -32,90 +46,119 @@ dotnet nuget locals all --clear
## How to use `C2CS`
-To generate bindings for a C library you need to use a configuration `.json` file which specifies the input to C2CS.
+To generate bindings for a C library you need to use a configuration `.json` file which specifies the input to C2CS. See the next sub-section below for documention on each property. See the [Hello World `config.json` file](src/cs/examples/helloworld/helloworld-c/config.json) for an example with annotated comments.
```json
{
- "inputFilePath": "path/to/library.h",
- "outputFilePath": "path/to/library.cs"
+ "$schema": "https://github.com/bottlenoselabs/c2cs/schema.json",
+ "directory": "path/to/my_c_library/ast",
+ "ast": {
+ "input_file": "path/to/my_c_library/include/my_c_library.h"
+ },
+ "cs": {
+ "output_file": "path/to/my_c_library/cs/my_c_library.cs"
+ }
}
```
-By default running `c2cs` via terminal will search for a `config.json` file in the current directory. If you want to use a specific `.json` file, specify the file path as the first argument: `c2cs myConfig.json`
+By default running `c2cs` via terminal will search for a `config.json` file in the current directory. If you want to use a specific `.json` file, specify the file path as the first argument: `c2cs -c myConfig.json`.
### Configuration `.json` properties
-#### `inputFilePath`
-
-Path of the input `.h` header file.
-
-#### `outputFilePath`
-
-Path of the output C# `.cs` file. If not specified, defaults to a file path using the current directory, a file name without extension that matches the `inputFilePath`, and a `.cs` file name extension.
-
-#### `abstractSyntaxTreeOutputFilePath`
-
-Path of the intermediate output abstract syntax tree `.json` file. If not specified, defaults to a random temporary file.
-
-#### `libraryName`
-
-The name of the dynamic link library (without the file extension) used for platform invoke (P/Invoke) with C#. If not specified, the library name is the same as the name of the `inputFilePath` without the directory name and without the file extension.
-
-#### `namespaceName`
-
-The name of the namespace to be used for the C# static class. If not specified, the namespace is the same as the `libraryName`.
-
-#### `className`
-
-The name of the C# static class. If not specified, the class name is the same as the `libraryName`.
-
-#### `headerCodeRegionFilePath`
-
-Path of the text file which to add the file's contents to the top of the C# file. Useful for comments, extra namespace using statements, or additional code that needs to be added to the generated C# file.
+The configuration properties are documented in the schema file: https://github.com/bottlenoselabs/c2cs/schema.json. By adding the schema to your JSON file, as seen in the example above, you can get intellisense in Visual Studio Code or your text editor of choice.
-#### `footerCodeRegionFilePath`
+## Cross-parsing with `C2CS`
-Path of the text file which to add the file's contents to the bottom of the C# file. Useful for comments or additional code that needs to be added to the generated C# file.
+What if you want to generate bindings for each platform in one `.cs` file? Cross-parsing is the way to do that.
-#### `mappedTypeNames`
+Let's take a look at a more complicated example by adding multiple target platforms to generate C# bindings for. (Omitting this information generates C# bindings using the host platform as the target.) Each target platform is a [Clang "target triple"](https://clang.llvm.org/docs/CrossCompilation.html) in the form of `arch-vendor-os[-environment]`. This is basically "cross-parsing" (as opposed to cross-compilation) of the C header `.h` file.
-Pairs of strings for re-mapping type names. Each pair has source name and a target name. The source name may be found when parsing C code and get mapped to the target name when generating C# code. Does not change the type's bit layout.
-
-#### `isEnabledFindSdk`
-
-Determines whether the software development kit (SDK) for C/C++ is attempted to be found. Default is `true`. If `true`, the C/C++ header files for the current operating system are attempted to be found. In such a case, if the C/C++ header files can not be found, then an error is generated which halts the program. If `false`, the C/C++ header files will likely be missing causing Clang to generate parsing errors which also halts the program. In such a case, the missing C/C++ header files can be supplied to Clang using `clangArguments` such as `"-isystemPATH/TO/SYSTEM/HEADER/DIRECTORY"`.
-
-#### `machineBitWidth`
-
-The bit width of the computer architecture to use when parsing C code. Default is `null`. If `null`, the bit width of host operating system's computer architecture is used. E.g. the default for x64 Windows is `64`. Possible values are `null`, `32` where pointers are 4 bytes, or `64` where pointers are 8 bytes.
-
-#### `includeDirectories`
-
-Search directory paths to use for `#include` usages when parsing C code. If `null`, uses the directory path of `inputFilePath`.
-
-#### `defines`
-
-Object-like macros to use when parsing C code.
-
-#### `excludedHeaderFiles`
-
-C header file names to exclude. File names are relative to `includeDirectories`.
-
-#### `ignoredTypeNames`
-
-Type names that may be found when parsing C code that will be ignored when generating C# code. Types are ignored after mapping type names using `mappedTypeNames`.
+```json
+{
+ "$schema": "https://github.com/bottlenoselabs/c2cs/schema.json",
+ "directory": "path/to/my_c_library/ast",
+ "ast": {
+ "input_file": "path/to/my_c_library/include/my_c_library.h",
+ "platforms": {
+ "aarch64-pc-windows-msvc": {},
+ "x86_64-pc-windows-msvc": {},
+ "aarch64-apple-darwin": {},
+ "x86_64-apple-darwin": {},
+ "aarch64-unknown-linux-gnu": {},
+ "x86_64-unknown-linux-gnu": {}
+ }
+ },
+ "cs": {
+ "output_file": "path/to/my_c_library/cs/my_c_library.cs"
+ }
+}
+```
-#### `opaqueTypeNames`
+The only problem with this approach is that sometimes a Clang "target triple" may not not be available or work correctly with your version of Clang that is installed for your host operating system.
+- macOS Apple Sillicon `aarch64-apple-darwin` may not be understood in your version of Clang that is installed.
+- I found a bug where "cross-parsing" from Ubuntu 20.04 as the host `x86_64-unknown-linux-gnu` to Windows `x86_64-pc-windows-msvc` results in wrong type size information.
+
+Thus, what I recommend is that different configuration files are used for each host to parse the C header `.h` file. Then use `c2cs ast -c config_ast_x.json` to generate the ASTs (abstract syntax trees) for each Clang target triple.
-Type names that may be found when parsing C code that will be interpreted as opaque types. Opaque types are often used with a pointer to hide the information about the bit layout behind the pointer.
+`config_ast_windows.json`
+```json
+{
+ "$schema": "https://github.com/bottlenoselabs/c2cs/schema.json",
+ "directory": "path/to/my_c_library/ast",
+ "ast": {
+ "input_file": "path/to/my_c_library/include/my_c_library.h",
+ "platforms": {
+ "aarch64-pc-windows-msvc": {},
+ "x86_64-pc-windows-msvc": {}
+ }
+ }
+}
+```
-#### `functionNamesWhitelist`
+`config_ast_macos.json`
+```json
+{
+ "$schema": "https://github.com/bottlenoselabs/c2cs/schema.json",
+ "directory": "path/to/my_c_library/ast",
+ "ast": {
+ "input_file": "path/to/my_c_library/include/my_c_library.h",
+ "platforms": {
+ "aarch64-apple-darwin": {},
+ "x86_64-apple-darwin": {},
+ "aarch64-apple-ios": {}
+ }
+ }
+}
+```
-The C function names to explicitly include when parsing C code. Default is `null`. If `null`, no white list applies to which all C function names that are found are eligible for C# code generation. Note that C function names which are excluded also exclude any transitive types.
+`config_ast_linux.json`
+```json
+{
+ "$schema": "https://github.com/bottlenoselabs/c2cs/schema.json",
+ "directory": "path/to/my_c_library/ast",
+ "ast": {
+ "input_file": "path/to/my_c_library/include/my_c_library.h",
+ "platforms": {
+ "aarch64-unknown-linux-gnu": {},
+ "x86_64-unknown-linux-gnu": {},
+ "aarch64-linux-android": {}
+ }
+ }
+}
+```
-#### `clangArguments`
+Once the AST files are generated, move them all over to any operating system and generate the C# bindings for all of them at once using `c2cs cs -c config_cs.json`.
-Additional Clang arguments to use when parsing C code.
+`config_cs.json`
+```json
+{
+ "$schema": "https://github.com/bottlenoselabs/c2cs/schema.json",
+ "directory": "path/to/my_c_library/ast",
+ "cs": {
+ "output_file": "path/to/my_c_library/cs/my_c_library.cs"
+ }
+}
+```
## How to use `C2CS.Runtime`
@@ -163,6 +206,60 @@ Open `./C2CS.sln`
`dotnet build`
+## Debugging `C2CS` from source
+
+### Debugging using logging
+
+Structured logging is added for sanity checking of normal/expected operation. It is also extremely helpful for diagnosing or digging into a problem. In more advanced situations it is used for automated black box testing. Any log can easily be identifiable back to the code via a quick search.
+
+An example of some logging output for console:
+
+```
+2022-31-03 01:54:24 info: [0] Configuration load: Success. Path: path/to/c2cs/bin/helloworld-c/Debug/net6.0/config.json.
+2022-31-03 01:54:24 info: [2] => Extract AST C - Started
+2022-31-03 01:54:24 info: [5] => Extract AST C => Install Clang macOS - Step started
+2022-31-03 01:54:24 trce: [8] => Extract AST C => Install Clang macOS - Success
+2022-31-03 01:54:24 info: [6] => Extract AST C => Install Clang macOS - Step finished in 0.001 seconds
+2022-31-03 01:54:24 info: [5] => Extract AST C => Parse x86_64-pc-windows - Step started
+2022-31-03 01:54:25 trce: [10] => Extract AST C => Parse x86_64-pc-windows - Success. Path: path/to/c2cs/src/cs/examples/helloworld/helloworld-c/my_c_library/include/my_c_library.h ; Clang arguments: --language=c --std=c11 -Wno-pragma-once-outside-header -fno-blocks --include-directory=/Users/lstranks/Programming/bottlenose/c2cs/src/cs/examples/helloworld/helloworld-c/my_c_library/include --target=x86_64-pc-windows ; Diagnostics: 0
+2022-31-03 01:54:25 info: [6] => Extract AST C => Parse x86_64-pc-windows - Step finished in 0.119 seconds
+2022-31-03 01:54:25 info: [5] => Extract AST C => Extract x86_64-pc-windows - Step started
+2022-31-03 01:54:25 trce: [13] => Extract AST C => Extract x86_64-pc-windows - Translation unit my_c_library.h
+2022-31-03 01:54:25 trce: [17] => Extract AST C => Extract x86_64-pc-windows - Enum my_enum_week_day
+2022-31-03 01:54:25 trce: [22] => Extract AST C => Extract x86_64-pc-windows - Type signed int
+2022-31-03 01:54:25 trce: [16] => Extract AST C => Extract x86_64-pc-windows - Function hello_world
+2022-31-03 01:54:25 trce: [22] => Extract AST C => Extract x86_64-pc-windows - Type void
+2022-31-03 01:54:25 trce: [16] => Extract AST C => Extract x86_64-pc-windows - Function pass_string
+2022-31-03 01:54:25 trce: [22] => Extract AST C => Extract x86_64-pc-windows - Type char*
+2022-31-03 01:54:25 trce: [22] => Extract AST C => Extract x86_64-pc-windows - Type char
+2022-31-03 01:54:25 trce: [16] => Extract AST C => Extract x86_64-pc-windows - Function pass_integers_by_value
+2022-31-03 01:54:25 trce: [16] => Extract AST C => Extract x86_64-pc-windows - Function pass_integers_by_reference
+2022-31-03 01:54:25 trce: [22] => Extract AST C => Extract x86_64-pc-windows - Type uint16_t*
+2022-31-03 01:54:25 trce: [22] => Extract AST C => Extract x86_64-pc-windows - Type int32_t*
+2022-31-03 01:54:25 trce: [22] => Extract AST C => Extract x86_64-pc-windows - Type uint64_t*
+2022-31-03 01:54:25 trce: [16] => Extract AST C => Extract x86_64-pc-windows - Function pass_enum
+2022-31-03 01:54:25 trce: [12] => Extract AST C => Extract x86_64-pc-windows - Success
+2022-31-03 01:54:25 info: [6] => Extract AST C => Extract x86_64-pc-windows - Step finished in 0.026 seconds
+2022-31-03 01:54:25 info: [5] => Extract AST C => Write x86_64-pc-windows - Step started
+2022-31-03 01:54:25 trce: [25] => Extract AST C => Write x86_64-pc-windows - Write abstract syntax tree C: Success. Path: path/to/c2cs/src/cs/examples/helloworld/helloworld-c/my_c_library/ast/x86_64-pc-windows.json
+2022-31-03 01:54:25 info: [6] => Extract AST C => Write x86_64-pc-windows - Step finished in 0.086 seconds
+...
+2022-31-03 01:54:25 info: [3] => Extract AST C - Success in 0.495 seconds
+```
+
+Things to notice from left to right:
+
+- Date
+- Time
+- Log level:
+ - `trce` stands for "trace". Ignorable at a glance; used for verbose information about what the program is doing exactly.
+ - `info`. Used for general higher level information about what the program is doing. Good for building automation tests from logging.
+ - `warn` stands for "warning". Suspicious; indicative of an expected but undesired outcome. Does not halt the program.
+ - `error`. Unacceptable; indicative of an unexpected result which should get fixed. Does not halt the program.
+ - `crit`. Crash; gracefully exit the program with a stack trace.
+- `[number]`: Used for automated tests and otherwise quick searching. Each kind of log is easily identifiable by a unique numeric identifier. E.g., when any use case begins it is 2. When any use case end successfully it is 3.
+- `=>`: The scope of the log. Helps keep track of the context of the log. Scopes can be nested with more than one `=>`. E.g. there is a scope for the use case of "Extract AST C" and a scope for "Extract x86_64-pc-windows". `x86_64-pc-windows` is the target platform to parse the C code with Clang.
+
## Examples
Here you will find examples of C libraries being demonstrated with `C2CS` as smoke tests or otherwise used directly.
diff --git a/ext/clang/include/clang-c/Index.h b/ext/clang/include/clang-c/Index.h
index e305283b..f28601c3 100644
--- a/ext/clang/include/clang-c/Index.h
+++ b/ext/clang/include/clang-c/Index.h
@@ -33,7 +33,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 61
+#define CINDEX_VERSION_MINOR 62
#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1))
@@ -2568,7 +2568,55 @@ enum CXCursorKind {
*/
CXCursor_OMPScanDirective = 287,
- CXCursor_LastStmt = CXCursor_OMPScanDirective,
+ /** OpenMP tile directive.
+ */
+ CXCursor_OMPTileDirective = 288,
+
+ /** OpenMP canonical loop.
+ */
+ CXCursor_OMPCanonicalLoop = 289,
+
+ /** OpenMP interop directive.
+ */
+ CXCursor_OMPInteropDirective = 290,
+
+ /** OpenMP dispatch directive.
+ */
+ CXCursor_OMPDispatchDirective = 291,
+
+ /** OpenMP masked directive.
+ */
+ CXCursor_OMPMaskedDirective = 292,
+
+ /** OpenMP unroll directive.
+ */
+ CXCursor_OMPUnrollDirective = 293,
+
+ /** OpenMP metadirective directive.
+ */
+ CXCursor_OMPMetaDirective = 294,
+
+ /** OpenMP loop directive.
+ */
+ CXCursor_OMPGenericLoopDirective = 295,
+
+ /** OpenMP teams loop directive.
+ */
+ CXCursor_OMPTeamsGenericLoopDirective = 296,
+
+ /** OpenMP target teams loop directive.
+ */
+ CXCursor_OMPTargetTeamsGenericLoopDirective = 297,
+
+ /** OpenMP parallel loop directive.
+ */
+ CXCursor_OMPParallelGenericLoopDirective = 298,
+
+ /** OpenMP target parallel loop directive.
+ */
+ CXCursor_OMPTargetParallelGenericLoopDirective = 299,
+
+ CXCursor_LastStmt = CXCursor_OMPTargetParallelGenericLoopDirective,
/**
* Cursor that represents the translation unit itself.
@@ -3274,8 +3322,9 @@ enum CXTypeKind {
CXType_UAccum = 37,
CXType_ULongAccum = 38,
CXType_BFloat16 = 39,
+ CXType_Ibm128 = 40,
CXType_FirstBuiltin = CXType_Void,
- CXType_LastBuiltin = CXType_BFloat16,
+ CXType_LastBuiltin = CXType_Ibm128,
CXType_Complex = 100,
CXType_Pointer = 101,
@@ -3368,7 +3417,8 @@ enum CXTypeKind {
CXType_OCLIntelSubgroupAVCImeDualRefStreamin = 175,
CXType_ExtVector = 176,
- CXType_Atomic = 177
+ CXType_Atomic = 177,
+ CXType_BTFTagAttributed = 178
};
/**
@@ -3394,6 +3444,7 @@ enum CXCallingConv {
CXCallingConv_PreserveMost = 14,
CXCallingConv_PreserveAll = 15,
CXCallingConv_AArch64VectorCall = 16,
+ CXCallingConv_SwiftAsync = 17,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
@@ -3866,7 +3917,7 @@ enum CXTypeNullabilityKind {
/**
* Generally behaves like Nullable, except when used in a block parameter that
* was imported into a swift async method. There, swift will assume that the
- * parameter can get null even if no error occured. _Nullable parameters are
+ * parameter can get null even if no error occurred. _Nullable parameters are
* assumed to only get null on error.
*/
CXTypeNullability_NullableResult = 4
diff --git a/mingw-w64-x86_64.cmake b/mingw-w64-x86_64.cmake
deleted file mode 100644
index c7dec617..00000000
--- a/mingw-w64-x86_64.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-set(CMAKE_SYSTEM_NAME Windows)
-set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
-
-# cross compilers to use for C, C++ and Fortran
-set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
-set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
-set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
-set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
-
-# target environment on the build host system
-set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
-
-# modify default behavior of FIND_XXX() commands
-set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
-set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-
-set(CMAKE_C_FLAGS_INIT "-static-libgcc -static-libstdc++")
-set(CMAKE_CXX_FLAGS_INIT "-static-libgcc -static-libstdc++")
\ No newline at end of file
diff --git a/schema.json b/schema.json
new file mode 100644
index 00000000..c4002760
--- /dev/null
+++ b/schema.json
@@ -0,0 +1 @@
+{"type":"object","properties":{"directory":{"type":"string","description":"Path of the input and output abstract syntax tree directory. By default, the directory will be used to write a \u0060.json\u0060 file for each target platform\u0027s abstract syntax tree that has been extracted. By default, the same abstract syntax tree \u0060.json\u0060 files will then be read when generating C# code."},"ast":{"type":"object","properties":{"WorkingDirectory":{"type":"string"},"input_file":{"type":"string","description":"Path of the input \u0060.h\u0060 header file containing C code."},"platforms":{"type":"object","additionalProperties":{"type":"object","properties":{"find_system_headers":{"type":"boolean","description":"Determines whether system C/C\u002B\u002B headers are attempted to be found and passed to Clang. Default is \u0060true\u0060."},"include":{"type":"array","items":{"type":"string","description":"Search directory paths to use for \u0060#include\u0060 usages when parsing C code."},"description":"Search directory paths to use for \u0060#include\u0060 usages when parsing C code."},"defines":{"type":"array","items":{"type":"string","description":"Object-like macros to use when parsing C code."},"description":"Object-like macros to use when parsing C code."},"exclude":{"type":"array","items":{"type":"string","description":"C header file names to exclude. File names are relative to the \u0060IncludeDirectories\u0060 property."},"description":"C header file names to exclude. File names are relative to the \u0060IncludeDirectories\u0060 property."},"function_names":{"type":"array","items":{"type":"string","description":"The C function names to explicitly include when parsing C code. Default is \u0060null\u0060. If \u0060null\u003C\u0060, no white list applies. Note that C function names which are excluded also exclude any transitive types."},"description":"The C function names to explicitly include when parsing C code. Default is \u0060null\u0060. If \u0060null\u003C\u0060, no white list applies. Note that C function names which are excluded also exclude any transitive types."},"opaque_names":{"type":"array","items":{"type":"string","description":"Type names that may be found when parsing C code that will be interpreted as opaque types. Opaque types are often used with a pointer to hide the information about the bit layout behind the pointer."},"description":"Type names that may be found when parsing C code that will be interpreted as opaque types. Opaque types are often used with a pointer to hide the information about the bit layout behind the pointer."},"clang_arguments":{"type":"array","items":{"type":"string","description":"Additional Clang arguments to use when parsing C code."},"description":"Additional Clang arguments to use when parsing C code."}},"description":"The target platform configurations for extracting the abstract syntax trees. Each target platform is a Clang target triple. See the C2CS docs for more details about what target platforms are available."},"description":"The target platform configurations for extracting the abstract syntax trees. Each target platform is a Clang target triple. See the C2CS docs for more details about what target platforms are available."}},"description":"The configuration for reading the \u0060.h\u0060 C header file."},"cs":{"type":"object","properties":{"WorkingDirectory":{"type":"string"},"output_file":{"type":"string","description":"Path of the output C# \u0060.cs\u0060 file."},"library_name":{"type":"string","description":"The name of the dynamic link library (without the file extension) used for platform invoke (P/Invoke) with C#. If not specified, the library name is the same as the name of the \u0060OutputFilePath\u0060 property without the directory name and without the file extension."},"namespace_name":{"type":"string","description":"The name of the namespace to be used for the C# static class. If not specified, the namespace is the same as the \u0060LibraryName\u0060 property."},"class_name":{"type":"string","description":"The name of the C# static class. If not specified, the class name is the same as the \u0060LibraryName\u0060 property."},"region_header_file":{"type":"string","description":"Path of the text file which to add the file\u0027s contents to the top of the C# file. Useful for comments, extra namespace using statements, or additional code that needs to be added to the generated C# file."},"region_footer_file":{"type":"string","description":"Path of the text file which to add the file\u0027s contents to the bottom of the C# file. Useful for comments or additional code that needs to be added to the generated C# file."},"mapped":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string"},"target":{"type":"string"}},"description":"Pairs of strings for re-mapping type names. Each pair has source name and a target name. Does not change the bit layout of types."},"description":"Pairs of strings for re-mapping type names. Each pair has source name and a target name. Does not change the bit layout of types."},"ignored":{"type":"array","items":{"type":"string","description":"Names of types, functions, enums, constants, or anything else that may be found when parsing C code that will be ignored when generating C# code. Type names are ignored after mapping type names using \u0060MappedTypeNames\u0060 property."},"description":"Names of types, functions, enums, constants, or anything else that may be found when parsing C code that will be ignored when generating C# code. Type names are ignored after mapping type names using \u0060MappedTypeNames\u0060 property."}},"description":"The configuration for writing the \u0060.cs\u0060 C# source code file."}}}
\ No newline at end of file
diff --git a/scripts/install-clang-macos.sh b/scripts/install-clang-macos.sh
new file mode 100755
index 00000000..dfe806e0
--- /dev/null
+++ b/scripts/install-clang-macos.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+
+INSTALL_DIR="$DIR/../lib"
+
+mkdir -p "$INSTALL_DIR"
+
+cp "/Library/Developer/CommandLineTools/usr/lib/libclang.dylib" "$INSTALL_DIR/libclang.dylib"
\ No newline at end of file
diff --git a/scripts/install-clang-x64-ubuntu_18_04.sh b/scripts/install-clang-x64-ubuntu_18_04.sh
new file mode 100755
index 00000000..d7d4f685
--- /dev/null
+++ b/scripts/install-clang-x64-ubuntu_18_04.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+
+DOWNLOAD_DIR="/tmp/c2cs"
+INSTALL_DIR="$DIR/../lib"
+
+mkdir -p "$DOWNLOAD_DIR"
+mkdir -p "$INSTALL_DIR"
+
+cd $DOWNLOAD_DIR
+curl -OL https://www.nuget.org/api/v2/package/libclang.runtime.ubuntu.18.04-x64
+unzip "libclang.runtime.ubuntu.18.04-x64"
+cd $DIR
+
+cp "$DOWNLOAD_DIR/runtimes/ubuntu.18.04-x64/native/libclang.so" "$INSTALL_DIR/libclang.so"
+rm -rf "$DOWNLOAD_DIR"
\ No newline at end of file
diff --git a/scripts/install-clang-x64-ubuntu_20_04.sh b/scripts/install-clang-x64-ubuntu_20_04.sh
new file mode 100755
index 00000000..7a1fbe8f
--- /dev/null
+++ b/scripts/install-clang-x64-ubuntu_20_04.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+
+DOWNLOAD_DIR="/tmp/c2cs"
+INSTALL_DIR="$DIR/../lib"
+
+mkdir -p "$DOWNLOAD_DIR"
+mkdir -p "$INSTALL_DIR"
+
+cd $DOWNLOAD_DIR
+curl -OL https://www.nuget.org/api/v2/package/libclang.runtime.ubuntu.20.04-x64
+unzip "libclang.runtime.ubuntu.20.04-x64"
+cd $DIR
+
+cp "$DOWNLOAD_DIR/runtimes/ubuntu.20.04-x64/native/libclang.so" "$INSTALL_DIR/libclang.so"
+rm -rf "$DOWNLOAD_DIR"
\ No newline at end of file
diff --git a/scripts/install-clang-x64-windows.sh b/scripts/install-clang-x64-windows.sh
new file mode 100755
index 00000000..349d5651
--- /dev/null
+++ b/scripts/install-clang-x64-windows.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+
+DOWNLOAD_DIR="/tmp/c2cs"
+INSTALL_DIR="$DIR/../lib"
+
+mkdir -p "$DOWNLOAD_DIR"
+mkdir -p "$INSTALL_DIR"
+
+cd $DOWNLOAD_DIR
+curl -OL https://www.nuget.org/api/v2/package/libclang.runtime.win-x64
+unzip "libclang.runtime.win-x64"
+cd $DIR
+
+cp "$DOWNLOAD_DIR/runtimes/win-x64/native/libclang.dll" "$INSTALL_DIR/libclang.dll"
+rm -rf "$DOWNLOAD_DIR"
\ No newline at end of file
diff --git a/src/cs/Directory.Build.props b/src/cs/Directory.Build.props
index 739cb6b1..2e2cf0cc 100644
--- a/src/cs/Directory.Build.props
+++ b/src/cs/Directory.Build.props
@@ -8,7 +8,7 @@
-
+
\ No newline at end of file
diff --git a/src/cs/examples/Directory.Build.props b/src/cs/examples/Directory.Build.props
index 8200ee98..e83daae0 100644
--- a/src/cs/examples/Directory.Build.props
+++ b/src/cs/examples/Directory.Build.props
@@ -11,11 +11,12 @@
false
-
+
- false
+ true
false
false
+ false
\ No newline at end of file
diff --git a/src/cs/examples/Directory.Build.targets b/src/cs/examples/Directory.Build.targets
index 72a6208f..01972cb5 100644
--- a/src/cs/examples/Directory.Build.targets
+++ b/src/cs/examples/Directory.Build.targets
@@ -2,4 +2,9 @@
+
+
+ false
+
+
\ No newline at end of file
diff --git a/src/cs/examples/helloworld/helloworld-c/Program.cs b/src/cs/examples/helloworld/helloworld-c/Program.cs
index fa79b8dc..3c9255af 100644
--- a/src/cs/examples/helloworld/helloworld-c/Program.cs
+++ b/src/cs/examples/helloworld/helloworld-c/Program.cs
@@ -12,12 +12,11 @@ private static void Main()
var rootDirectory = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "../../../.."));
if (!BuildLibrary(rootDirectory))
{
- // Error building C library
+ Console.WriteLine("Error building C library");
return;
}
GenerateBindingsCSharp();
- // GenerateBindingsCSharp(rootDirectory);
}
private static bool BuildLibrary(string rootDirectory)
@@ -30,19 +29,6 @@ private static bool BuildLibrary(string rootDirectory)
private static void GenerateBindingsCSharp()
{
- C2CS.Program.Main();
+ C2CS.Program.Main(Array.Empty());
}
-
-// private static void GenerateBindingsCSharp(string rootDirectory)
-// {
-// var arguments = @$"
-// cs
-// {rootDirectory}/src/cs/examples/helloworld/helloworld-c/my_c_library/ast/ast.json
-// -n
-// my_c_library_namespace
-// ";
-// var argumentsArray =
-// arguments.Split(new[] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
-// C2CS.Program.Main(argumentsArray);
-// }
}
diff --git a/src/cs/examples/helloworld/helloworld-c/config.json b/src/cs/examples/helloworld/helloworld-c/config.json
index 3dda08bb..019d5c38 100644
--- a/src/cs/examples/helloworld/helloworld-c/config.json
+++ b/src/cs/examples/helloworld/helloworld-c/config.json
@@ -1,19 +1,12 @@
{
- "inputFilePath": "../../../../src/cs/examples/helloworld/helloworld-c/my_c_library/include/my_c_library.h",
- "outputFilePath": "../../../../src/cs/examples/helloworld/helloworld-cs/my_c_library.cs",
- "abstractSyntaxTreeOutputFilePath": null,
- "libraryName": null,
- "namespaceName": "my_c_library_namespace",
- "className": null,
- "headerCodeRegionFilePath": null,
- "footerCodeRegionFilePath": null,
- "mappedTypeNames": null,
- "isEnabledFindSdk": true,
- "machineBitWidth": null,
- "includeDirectories": null,
- "defines": null,
- "excludedHeaderFiles": null,
- "ignoredTypeNames": null,
- "opaqueTypeNames": null,
- "clangArguments": null
+ "//schema": "Use `https://www.github.com/bottlenoselabs/c2cs/schema.json` or `path/to/c2cs/schema.json` for the schema. You can generate the schema at any time by using `c2cs schema` in terminal.",
+ "$schema": "../../../../../schema.json",
+ "directory": "../../../../src/cs/examples/helloworld/helloworld-c/my_c_library/ast",
+ "ast": {
+ "input_file": "../../../../src/cs/examples/helloworld/helloworld-c/my_c_library/include/my_c_library.h"
+ },
+ "cs": {
+ "output_file": "../../../../src/cs/examples/helloworld/helloworld-cs/my_c_library.cs",
+ "namespace_name": "my_c_library_namespace"
+ }
}
\ No newline at end of file
diff --git a/src/cs/examples/helloworld/helloworld-c/helloworld-c.csproj b/src/cs/examples/helloworld/helloworld-c/helloworld-c.csproj
index 7be72c3b..cee222c0 100644
--- a/src/cs/examples/helloworld/helloworld-c/helloworld-c.csproj
+++ b/src/cs/examples/helloworld/helloworld-c/helloworld-c.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/src/cs/examples/helloworld/helloworld-c/my_c_library/src/my_c_library.c b/src/cs/examples/helloworld/helloworld-c/my_c_library/src/my_c_library.c
index d8425602..53fa6335 100644
--- a/src/cs/examples/helloworld/helloworld-c/my_c_library/src/my_c_library.c
+++ b/src/cs/examples/helloworld/helloworld-c/my_c_library/src/my_c_library.c
@@ -5,7 +5,7 @@
void hello_world(void)
{
- printf("Hello, World!\n");
+ printf("Hello world from C!\n");
}
void pass_string(const char* s)
diff --git a/src/cs/examples/helloworld/helloworld-cs/helloworld-cs.csproj b/src/cs/examples/helloworld/helloworld-cs/helloworld-cs.csproj
index 4a62c57a..de673173 100644
--- a/src/cs/examples/helloworld/helloworld-cs/helloworld-cs.csproj
+++ b/src/cs/examples/helloworld/helloworld-cs/helloworld-cs.csproj
@@ -3,14 +3,9 @@
net6.0
-
+
-
-
-
-
-
diff --git a/src/cs/examples/helloworld/helloworld-cs/my_c_library.cs b/src/cs/examples/helloworld/helloworld-cs/my_c_library.cs
index 04749ebd..444f140d 100644
--- a/src/cs/examples/helloworld/helloworld-cs/my_c_library.cs
+++ b/src/cs/examples/helloworld/helloworld-cs/my_c_library.cs
@@ -25,26 +25,26 @@ public static unsafe partial class my_c_library
private const string LibraryName = "my_c_library";
// Function @ my_c_library.h:21:28
- [DllImport(LibraryName)]
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
public static extern void hello_world();
// Function @ my_c_library.h:22:28
- [DllImport(LibraryName)]
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
public static extern void pass_string(CString s);
// Function @ my_c_library.h:23:28
- [DllImport(LibraryName)]
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
public static extern void pass_integers_by_value(ushort a, int b, ulong c);
// Function @ my_c_library.h:24:28
- [DllImport(LibraryName)]
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
public static extern void pass_integers_by_reference(ushort* a, int* b, ulong* c);
// Function @ my_c_library.h:25:28
- [DllImport(LibraryName)]
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
public static extern void pass_enum(my_enum_week_day e);
- // Enum @ my_c_library.h:19:3
+ // Enum @ my_c_library.h:11:14
public enum my_enum_week_day : int
{
MY_ENUM_WEEK_DAY_UNKNOWN = 0,
diff --git a/src/cs/production/C2CS.Common/C2CS.Common.csproj b/src/cs/production/C2CS.Common/C2CS.Common.csproj
deleted file mode 100644
index 0b609123..00000000
--- a/src/cs/production/C2CS.Common/C2CS.Common.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- net6.0
- enable
- C2CS
- false
-
-
-
diff --git a/src/cs/production/C2CS.Common/Foundation/UseCases/IUseCaseRequest.cs b/src/cs/production/C2CS.Common/Foundation/UseCases/IUseCaseRequest.cs
deleted file mode 100644
index d193eee2..00000000
--- a/src/cs/production/C2CS.Common/Foundation/UseCases/IUseCaseRequest.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Diagnostics.CodeAnalysis;
-
-namespace C2CS;
-
-[SuppressMessage("Design", "CA1040:Avoid empty interfaces", Justification = "Marker interface.")]
-public interface IUseCaseRequest : IUseCaseRequest
-{
-}
-
-[SuppressMessage("Design", "CA1040:Avoid empty interfaces", Justification = "Marker interface.")]
-public interface IUseCaseRequest : IBaseUseCaseRequest
-{
-}
diff --git a/src/cs/production/C2CS.Common/Foundation/UseCases/IUseCaseRequestHandler.cs b/src/cs/production/C2CS.Common/Foundation/UseCases/IUseCaseRequestHandler.cs
deleted file mode 100644
index 1672678a..00000000
--- a/src/cs/production/C2CS.Common/Foundation/UseCases/IUseCaseRequestHandler.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace C2CS;
-
-public interface IUseCaseRequestHandler
- where TRequest : IUseCaseRequest
-{
- Task Handle(TRequest request, CancellationToken cancellationToken);
-}
-
-public interface IRequestHandler : IUseCaseRequestHandler
- where TRequest : IUseCaseRequest
-{
-}
diff --git a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseException.cs b/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseException.cs
deleted file mode 100644
index 3aa44afd..00000000
--- a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseException.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System;
-using System.Diagnostics;
-
-namespace C2CS;
-
-public class UseCaseException : Exception
-{
- public UseCaseException()
- : this(CreateMessage(string.Empty))
- {
- }
-
- public UseCaseException(string message)
- : base(CreateMessage(message))
- {
- }
-
- public UseCaseException(string message, Exception innerException)
- : base(CreateMessage(message), innerException)
- {
- }
-
- private static string CreateMessage(string message)
- {
- var name = UseCaseNamespaceName();
- return string.IsNullOrEmpty(message) ? name : $"{name}: {message}";
- }
-
- private static string UseCaseNamespaceName(int skipFrames = 3)
- {
- while (true)
- {
- var method = new StackFrame(skipFrames, false).GetMethod()!;
- var declaringType = method.DeclaringType;
- var typeNamespace = declaringType?.Namespace!;
- if (string.IsNullOrEmpty(typeNamespace))
- {
- skipFrames++;
- continue;
- }
-
- var currentNamespaceName = typeof(UseCaseException).Namespace!;
- if (!typeNamespace.StartsWith(currentNamespaceName, StringComparison.InvariantCulture))
- {
- skipFrames++;
- continue;
- }
-
- var candidateNamespaceName = typeNamespace[currentNamespaceName.Length..].Trim('.');
- const string useCasesNamespaceName = "UseCases.";
- if (candidateNamespaceName.StartsWith(useCasesNamespaceName, StringComparison.InvariantCulture))
- {
- candidateNamespaceName = candidateNamespaceName[useCasesNamespaceName.Length..];
- }
-
- return candidateNamespaceName;
- }
- }
-}
diff --git a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseHandler.cs b/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseHandler.cs
deleted file mode 100644
index 64089665..00000000
--- a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseHandler.cs
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using JetBrains.Annotations;
-
-namespace C2CS;
-
-[PublicAPI]
-public abstract class UseCaseHandler
- where TOutput : UseCaseOutput, new()
-{
- private readonly string _useCaseName;
- private readonly Stopwatch _stepStopwatch;
- private readonly UseCaseStepMetaData[] _stepsMetaData;
- private int _stepIndex;
-
- protected UseCaseHandler()
- {
- _useCaseName = GetUseCaseName();
- _stepStopwatch = new Stopwatch();
- _stepsMetaData = GetStepsMetaData().ToArray();
- }
-
- private IEnumerable GetStepsMetaData()
- {
- var methods = GetType().GetRuntimeMethods();
- var useCaseStepAttributes = methods
- .Select(x => x.GetCustomAttribute())
- .Where(x => x != null)
- .Cast()
- .ToArray();
-
- foreach (var attribute in useCaseStepAttributes)
- {
- var useCaseStepMetaData = new UseCaseStepMetaData
- {
- Name = attribute.StepName
- };
-
- yield return useCaseStepMetaData;
- }
- }
-
- protected DiagnosticsSink Diagnostics { get; } = new();
-
- public TOutput Execute(TInput input)
- {
- var response = Begin(input);
-
- try
- {
- Execute(input, response);
- }
- catch (Exception e)
- {
- Panic(e);
-
- if (Debugger.IsAttached)
- {
- throw;
- }
- }
-
- End(response);
- return response;
- }
-
- protected abstract void Execute(TInput input, TOutput output);
-
- private TOutput Begin(TInput request)
- {
- _stepStopwatch.Reset();
- GarbageCollect();
- Console.WriteLine(
- $"{_useCaseName}: Started.");
- return new TOutput();
- }
-
- private void End(TOutput response)
- {
- // _stepIndex = 0;
- response.WithDiagnostics(Diagnostics.GetAll());
-
- if (response.Status == UseCaseOutputStatus.Success)
- {
- Console.Write(
- $"{_useCaseName}: Finished successfully.");
- if (response.Diagnostics.Length > 0)
- {
- Console.WriteLine(
- $" However there are {response.Diagnostics.Length} diagnostics to report. This may be indicative of unexpected results. Please review the following diagnostics:");
- }
- else
- {
- Console.WriteLine();
- }
- }
- else
- {
- Console.WriteLine(
- $"{_useCaseName}: Finished unsuccessfully. Review the following diagnostics for reason(s) why:");
- }
-
- PrintDiagnostics(response.Diagnostics);
- GarbageCollect();
- }
-
- private void Panic(Exception e)
- {
- var diagnostic = new DiagnosticPanic(e);
- Diagnostics.Add(diagnostic);
- }
-
- protected void BeginStep()
- {
- var stepMetaData = _stepsMetaData[_stepIndex++];
- var stepCount = _stepsMetaData.Length;
- Console.WriteLine($"\tStarted step ({_stepIndex}/{stepCount}) '{stepMetaData.Name}'");
- _stepStopwatch.Start();
- GarbageCollect();
- }
-
- protected void EndStep()
- {
- var stepMetaData = _stepsMetaData[_stepIndex - 1];
- var stepCount = _stepsMetaData.Length;
- _stepStopwatch.Stop();
- Console.WriteLine(
- $"\tFinished step ({_stepIndex}/{stepCount}) '{stepMetaData.Name}' in {_stepStopwatch.Elapsed.TotalMilliseconds} ms");
- _stepStopwatch.Reset();
- GarbageCollect();
- }
-
- private string GetUseCaseName()
- {
- var type = GetType()!;
- var namespaceName = type.Namespace;
- var lastNamespaceIndex = namespaceName!.LastIndexOf('.');
- var name = namespaceName![(lastNamespaceIndex + 1)..];
- return name;
- }
-
- private static void PrintDiagnostics(ImmutableArray diagnostics)
- {
- foreach (var diagnostic in diagnostics)
- {
- Console.WriteLine(diagnostic);
- }
- }
-
- private static void GarbageCollect()
- {
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
- }
-}
diff --git a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseResponseUnit.cs b/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseResponseUnit.cs
deleted file mode 100644
index 9a5d3963..00000000
--- a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseResponseUnit.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Threading.Tasks;
-
-namespace C2CS;
-
-public readonly record struct UseCaseResponseUnit
-{
- // ReSharper disable once UnassignedReadonlyField
- public static readonly UseCaseResponseUnit Value;
-
- public static Task Task { get; } = System.Threading.Tasks.Task.FromResult(Value);
-
- public override string ToString() => "()";
-}
diff --git a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseStepAttribute.cs b/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseStepAttribute.cs
deleted file mode 100644
index cdd5fd46..00000000
--- a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseStepAttribute.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System;
-
-namespace C2CS;
-
-[AttributeUsage(
- AttributeTargets.Method,
- AllowMultiple = false,
- Inherited = false)]
-public sealed class UseCaseStepAttribute : Attribute
-{
- public string StepName { get; }
-
- public UseCaseStepAttribute(string stepName)
- {
- StepName = stepName;
- }
-}
diff --git a/src/cs/production/C2CS.Common/Platform/Platform.cs b/src/cs/production/C2CS.Common/Platform/Platform.cs
deleted file mode 100644
index 10143494..00000000
--- a/src/cs/production/C2CS.Common/Platform/Platform.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace C2CS;
-
-///
-/// The collection of utilities for platform interoperability with native libraries in C#.
-///
-public static class Platform
-{
- ///
- /// Gets the current .
- ///
- public static RuntimeOperatingSystem HostOperatingSystem => GetRuntimeOperatingSystem();
-
- ///
- /// Gets the current .
- ///
- public static RuntimeArchitecture HostArchitecture => GetRuntimeArchitecture();
-
- ///
- /// Gets the library file name extension given a .
- ///
- /// The runtime platform.
- ///
- /// A containing the library file name extension for the
- /// .
- ///
- /// is not available yet with .NET 5.
- /// is not a known valid value.
- public static string LibraryFileNameExtension(RuntimeOperatingSystem operatingSystem)
- {
- return operatingSystem switch
- {
- RuntimeOperatingSystem.Windows => ".dll",
- RuntimeOperatingSystem.Xbox => ".dll",
- RuntimeOperatingSystem.macOS => ".dylib",
- RuntimeOperatingSystem.tvOS => ".dylib",
- RuntimeOperatingSystem.iOS => ".dylib",
- RuntimeOperatingSystem.Linux => ".so",
- RuntimeOperatingSystem.FreeBSD => ".so",
- RuntimeOperatingSystem.Android => ".so",
- RuntimeOperatingSystem.PlayStation => ".so",
- RuntimeOperatingSystem.Browser => throw new NotImplementedException(),
- RuntimeOperatingSystem.Switch => throw new NotImplementedException(),
- RuntimeOperatingSystem.Unknown => throw new NotImplementedException(),
- _ => throw new ArgumentOutOfRangeException(nameof(operatingSystem), operatingSystem, null)
- };
- }
-
- ///
- /// Gets the library file name prefix for a .
- ///
- /// The runtime platform.
- ///
- /// A containing the library file name prefix for the
- /// .
- ///
- /// is not available yet with .NET 5.
- /// is not a known valid value.
- public static string LibraryFileNamePrefix(RuntimeOperatingSystem targetOperatingSystem)
- {
- switch (targetOperatingSystem)
- {
- case RuntimeOperatingSystem.Windows:
- case RuntimeOperatingSystem.Xbox:
- return string.Empty;
- case RuntimeOperatingSystem.macOS:
- case RuntimeOperatingSystem.tvOS:
- case RuntimeOperatingSystem.iOS:
- case RuntimeOperatingSystem.Linux:
- case RuntimeOperatingSystem.FreeBSD:
- case RuntimeOperatingSystem.Android:
- case RuntimeOperatingSystem.PlayStation:
- return "lib";
- case RuntimeOperatingSystem.Browser:
- case RuntimeOperatingSystem.Switch:
- case RuntimeOperatingSystem.Unknown:
- throw new NotImplementedException();
- default:
- throw new ArgumentOutOfRangeException(nameof(targetOperatingSystem), targetOperatingSystem, null);
- }
- }
-
- private static RuntimeArchitecture GetRuntimeArchitecture()
- {
- return RuntimeInformation.OSArchitecture switch
- {
- Architecture.Arm64 => RuntimeArchitecture.ARM64,
- Architecture.Arm => RuntimeArchitecture.ARM32,
- Architecture.X86 => RuntimeArchitecture.X86,
- Architecture.X64 => RuntimeArchitecture.X64,
- Architecture.Wasm => RuntimeArchitecture.Unknown,
- Architecture.S390x => RuntimeArchitecture.Unknown,
- _ => throw new ArgumentOutOfRangeException()
- };
- }
-
- private static RuntimeOperatingSystem GetRuntimeOperatingSystem()
- {
- if (OperatingSystem.IsWindows())
- {
- return RuntimeOperatingSystem.Windows;
- }
-
- if (OperatingSystem.IsMacOS())
- {
- return RuntimeOperatingSystem.macOS;
- }
-
- if (OperatingSystem.IsLinux())
- {
- return RuntimeOperatingSystem.Linux;
- }
-
- if (OperatingSystem.IsAndroid())
- {
- return RuntimeOperatingSystem.Android;
- }
-
- if (OperatingSystem.IsIOS())
- {
- return RuntimeOperatingSystem.iOS;
- }
-
- if (OperatingSystem.IsTvOS())
- {
- return RuntimeOperatingSystem.tvOS;
- }
-
- if (OperatingSystem.IsBrowser())
- {
- return RuntimeOperatingSystem.Browser;
- }
-
- return RuntimeOperatingSystem.Unknown;
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/C2CS.Feature.BindgenCSharp.csproj b/src/cs/production/C2CS.Feature.BindgenCSharp/C2CS.Feature.BindgenCSharp.csproj
deleted file mode 100644
index 6a88ba88..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/C2CS.Feature.BindgenCSharp.csproj
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- net6.0
- enable
- enable
- $(NoWarn);CA1724
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpConstant.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpConstant.cs
deleted file mode 100644
index 710d0289..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpConstant.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpConstant : CSharpNode
-{
- public string Type;
- public string Value;
-
- public CSharpConstant(
- string name,
- string locationComment,
- string type,
- string value)
- : base(name, locationComment)
- {
- Type = type;
- Value = value;
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpEnum.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpEnum.cs
deleted file mode 100644
index 546414c4..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpEnum.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpEnum(
- string Name,
- string CodeLocationComment,
- CSharpType IntegerType,
- ImmutableArray Values)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly CSharpType IntegerType = IntegerType;
- public readonly ImmutableArray Values = Values;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpEnumValue.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpEnumValue.cs
deleted file mode 100644
index 4ad407fc..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpEnumValue.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpEnumValue(
- string Name,
- string CodeLocationComment,
- long Value)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly long Value = Value;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunction.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunction.cs
deleted file mode 100644
index 1a7e50c2..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunction.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpFunction(
- string Name,
- string CodeLocationComment,
- CSharpFunctionCallingConvention CallingConvention,
- CSharpType ReturnType,
- ImmutableArray Parameters)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly CSharpFunctionCallingConvention CallingConvention = CallingConvention;
- public readonly ImmutableArray Parameters = Parameters;
- public readonly CSharpType ReturnType = ReturnType;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionParameter.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionParameter.cs
deleted file mode 100644
index 19151110..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionParameter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpFunctionParameter(
- string Name,
- string CodeLocationComment,
- CSharpType Type)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly CSharpType Type = Type;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionPointer.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionPointer.cs
deleted file mode 100644
index 9d9f0130..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionPointer.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpFunctionPointer(
- string Name,
- string CodeLocationComment,
- CSharpType ReturnType,
- ImmutableArray Parameters)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly ImmutableArray Parameters = Parameters;
- public readonly CSharpType ReturnType = ReturnType;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionPointerParameter.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionPointerParameter.cs
deleted file mode 100644
index 741b77a7..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpFunctionPointerParameter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpFunctionPointerParameter(
- string Name,
- string CodeLocationComment,
- CSharpType Type)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly CSharpType Type = Type;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpNode.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpNode.cs
deleted file mode 100644
index 26549e89..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpNode.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpNode(
- string? Name,
- string? CodeLocationComment)
-{
- public readonly string CodeLocationComment =
- string.IsNullOrEmpty(CodeLocationComment) ? string.Empty : CodeLocationComment;
-
- public readonly string Name = string.IsNullOrEmpty(Name) ? string.Empty : Name;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return $"{Name} {CodeLocationComment}";
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpOpaqueType.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpOpaqueType.cs
deleted file mode 100644
index 15b90510..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpOpaqueType.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpOpaqueType(
- string Name,
- string CodeLocationComment)
- : CSharpNode(Name, CodeLocationComment)
-{
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpPseudoEnum.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpPseudoEnum.cs
deleted file mode 100644
index 55204e4f..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpPseudoEnum.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpPseudoEnum(
- string Name,
- string CodeLocationComment,
- CSharpType IntegerType,
- ImmutableArray Values)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly CSharpType IntegerType = IntegerType;
- public readonly ImmutableArray Values = Values;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpPseudoEnumValue.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpPseudoEnumValue.cs
deleted file mode 100644
index c3477919..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpPseudoEnumValue.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpPseudoEnumValue(
- string Name,
- string CodeLocationComment,
- long Value)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly long Value = Value;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpStruct.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpStruct.cs
deleted file mode 100644
index afc68d05..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpStruct.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpStruct(
- string CodeLocationComment,
- CSharpType Type,
- ImmutableArray Fields,
- ImmutableArray NestedStructs)
- : CSharpNode(Type.Name, CodeLocationComment)
-{
- public readonly ImmutableArray Fields = Fields;
- public readonly ImmutableArray NestedStructs = NestedStructs;
- public readonly CSharpType Type = Type;
-
- // Required for debugger string with records
- // ReSharper disable once RedundantOverriddenMember
- public override string ToString()
- {
- return base.ToString();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpTypedef.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpTypedef.cs
deleted file mode 100644
index dbdb283b..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Data/CSharpTypedef.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Data;
-
-public record CSharpTypedef(
- string Name,
- string CodeLocationComment,
- CSharpType UnderlyingType)
- : CSharpNode(Name, CodeLocationComment)
-{
- public readonly CSharpType UnderlyingType = UnderlyingType;
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/MacroObjectAlreadyExistsDiagnostic.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/MacroObjectAlreadyExistsDiagnostic.cs
deleted file mode 100644
index 9adab9f7..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/MacroObjectAlreadyExistsDiagnostic.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Diagnostics;
-
-public class MacroObjectAlreadyExistsDiagnostic : Diagnostic
-{
- public MacroObjectAlreadyExistsDiagnostic(string name, ClangLocation loc)
- : base(DiagnosticSeverity.Warning)
- {
- Summary =
- $"The object-like macro '{name}' at {loc.FilePath}:{loc.LineNumber}:{loc.LineColumn} already previously exists.";
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/MacroObjectNotTranspiledDiagnostic.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/MacroObjectNotTranspiledDiagnostic.cs
deleted file mode 100644
index e8fba9d9..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/MacroObjectNotTranspiledDiagnostic.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Diagnostics;
-
-public class MacroObjectNotTranspiledDiagnostic : Diagnostic
-{
- public MacroObjectNotTranspiledDiagnostic(string name, ClangLocation loc)
- : base(DiagnosticSeverity.Warning)
- {
- Summary =
- $"The object-like macro '{name}' at {loc.FilePath}:{loc.LineNumber}:{loc.LineColumn} was not transpiled.";
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/SystemTypedefDiagnostic.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/SystemTypedefDiagnostic.cs
deleted file mode 100644
index 31117771..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Diagnostics/SystemTypedefDiagnostic.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.BindgenCSharp.Diagnostics;
-
-public class SystemTypedefDiagnostic : Diagnostic
-{
- public SystemTypedefDiagnostic(string typeName, ClangLocation loc, string underlyingTypeName)
- : base(DiagnosticSeverity.Warning)
- {
- Summary =
- $"The typedef '{typeName}' at {loc.FilePath}:{loc.LineNumber}:{loc.LineColumn} is a system alias to the system type '{underlyingTypeName}'. If you intend to have cross-platform bindings this is a problem; please create an issue on GitHub.";
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Input.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/Input.cs
deleted file mode 100644
index d8fa2777..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Input.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-using C2CS.Feature.BindgenCSharp.Data;
-
-namespace C2CS.Feature.BindgenCSharp;
-
-public class Input
-{
- public string InputFilePath { get; }
-
- public string OutputFilePath { get; }
-
- public ImmutableArray TypeAliases { get; }
-
- public ImmutableArray IgnoredTypeNames { get; }
-
- public string LibraryName { get; }
-
- public string ClassName { get; }
-
- public string NamespaceName { get; }
-
- public string HeaderCodeRegion { get; }
-
- public string FooterCodeRegion { get; }
-
- public Input(
- string? inputFilePath,
- string? outputFilePath,
- string? libraryName,
- string? @namespace,
- string? className,
- ImmutableArray? mappedTypeNames,
- ImmutableArray? ignoredTypeNames,
- string? headerCodeRegionFilePath,
- string? footerCodeRegionFilePath)
- {
- InputFilePath = VerifyInputFilePath(inputFilePath);
- OutputFilePath = VerifyOutputFilePath(outputFilePath, InputFilePath);
- ClassName = VerifyClassName(className, OutputFilePath);
- LibraryName = VerifyLibraryName(libraryName, ClassName);
- NamespaceName = VerifyNamespace(@namespace, LibraryName);
- TypeAliases = VerifyTypeAliases(mappedTypeNames);
- IgnoredTypeNames = VerifyIgnoredTypeNames(ignoredTypeNames);
- HeaderCodeRegion = VerifyHeaderCodeRegion(headerCodeRegionFilePath);
- FooterCodeRegion = VerifyFooterCodeRegion(footerCodeRegionFilePath);
- }
-
- private static string VerifyInputFilePath(string? inputFilePath)
- {
- if (string.IsNullOrWhiteSpace(inputFilePath))
- {
- throw new UseCaseException("The input file can not be null, empty, or whitespace.");
- }
-
- if (!File.Exists(inputFilePath))
- {
- throw new UseCaseException($"The input file does not exist: {inputFilePath}");
- }
-
- return inputFilePath;
- }
-
- private static string VerifyOutputFilePath(string? outputFilePath, string inputFilePath)
- {
- if (!string.IsNullOrEmpty(outputFilePath))
- {
- return Path.GetFullPath(outputFilePath);
- }
-
- var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(inputFilePath);
- var defaultFilePath = Path.Combine(Environment.CurrentDirectory, $"{fileNameWithoutExtension}.cs");
- return defaultFilePath;
- }
-
- private static ImmutableArray VerifyTypeAliases(ImmutableArray? mappedTypeNames)
- {
- if (mappedTypeNames == null || mappedTypeNames.Value.IsDefaultOrEmpty)
- {
- return ImmutableArray.Empty;
- }
-
- var builder = ImmutableArray.CreateBuilder();
- foreach (var typeAlias in mappedTypeNames)
- {
- builder.Add(typeAlias);
- }
-
- return builder.ToImmutable();
- }
-
- private static ImmutableArray VerifyIgnoredTypeNames(ImmutableArray? ignoredTypeNames)
- {
- if (ignoredTypeNames == null || ignoredTypeNames.Value.IsDefaultOrEmpty)
- {
- return ImmutableArray.Empty;
- }
-
- var array = ignoredTypeNames.Value
- .Where(x => !string.IsNullOrEmpty(x))
- .Cast();
- return array.ToImmutableArray();
- }
-
- private static string VerifyLibraryName(string? libraryName, string className)
- {
- return !string.IsNullOrEmpty(libraryName) ? libraryName : className;
- }
-
- private static string VerifyNamespace(string? @namespace, string libraryName)
- {
- return !string.IsNullOrEmpty(@namespace) ? @namespace : libraryName;
- }
-
- private static string VerifyClassName(string? className, string outputFilePath)
- {
- string result;
- if (string.IsNullOrEmpty(className))
- {
- var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(outputFilePath);
- var firstIndexOfPeriod = fileNameWithoutExtension.IndexOf('.', StringComparison.InvariantCulture);
- result = firstIndexOfPeriod == -1
- ? fileNameWithoutExtension
- : fileNameWithoutExtension[..firstIndexOfPeriod];
- }
- else
- {
- result = className;
- }
-
- return result;
- }
-
- private static string VerifyHeaderCodeRegion(string? headerCodeRegionFilePath)
- {
- if (string.IsNullOrEmpty(headerCodeRegionFilePath))
- {
- return string.Empty;
- }
-
- var code = File.ReadAllText(headerCodeRegionFilePath);
- return code;
- }
-
- private static string VerifyFooterCodeRegion(string? footerCodeRegionFilePath)
- {
- if (string.IsNullOrEmpty(footerCodeRegionFilePath))
- {
- return string.Empty;
- }
-
- var code = File.ReadAllText(footerCodeRegionFilePath);
- return code;
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/UseCase.cs b/src/cs/production/C2CS.Feature.BindgenCSharp/UseCase.cs
deleted file mode 100644
index 49ccaeaf..00000000
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/UseCase.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-using C2CS.Feature.BindgenCSharp.Data;
-using C2CS.Feature.BindgenCSharp.Logic;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Data.Serialization;
-
-namespace C2CS.Feature.BindgenCSharp;
-
-public class UseCase : UseCaseHandler
-{
- protected override void Execute(Input input, Output output)
- {
- Validate(input);
-
- var abstractSyntaxTree = LoadCAbstractSyntaxTreeFromFileStorage(input.InputFilePath);
-
- var abstractSyntaxTreeCSharp = MapCAbstractSyntaxTreeToCSharp(
- abstractSyntaxTree,
- input.TypeAliases,
- input.IgnoredTypeNames,
- abstractSyntaxTree.Bitness,
- Diagnostics);
-
- var codeCSharp = GenerateCSharpCode(
- abstractSyntaxTreeCSharp,
- input.ClassName,
- input.LibraryName,
- input.NamespaceName,
- input.HeaderCodeRegion,
- input.FooterCodeRegion);
-
- WriteCSharpCodeToFileStorage(input.OutputFilePath, codeCSharp);
- }
-
- private static void Validate(Input request)
- {
- if (!File.Exists(request.InputFilePath))
- {
- throw new UseCaseException($"File does not exist: `{request.InputFilePath}`.");
- }
- }
-
- [UseCaseStep("Load C abstract syntax tree from file storage.")]
- private CAbstractSyntaxTree LoadCAbstractSyntaxTreeFromFileStorage(string inputFilePath)
- {
- BeginStep();
- var fileContents = File.ReadAllText(inputFilePath);
- var serializerOptions = new JsonSerializerOptions
- {
- WriteIndented = true,
- Converters =
- {
- new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
- }
- };
- var serializerContext = new CJsonSerializerContext(serializerOptions);
- var abstractSyntaxTree = JsonSerializer.Deserialize(fileContents, serializerContext.CAbstractSyntaxTree)!;
- EndStep();
-
- return abstractSyntaxTree;
- }
-
- [UseCaseStep("Map C abstract syntax tree to C#")]
- private CSharpAbstractSyntaxTree MapCAbstractSyntaxTreeToCSharp(
- CAbstractSyntaxTree abstractSyntaxTree,
- ImmutableArray typeAliases,
- ImmutableArray ignoredTypeNames,
- int bitness,
- DiagnosticsSink diagnostics)
- {
- BeginStep();
- var mapperParameters = new CSharpMapperParameters(
- typeAliases, ignoredTypeNames, bitness, diagnostics);
- var mapper = new CSharpMapper(mapperParameters);
- var result = mapper.AbstractSyntaxTree(abstractSyntaxTree);
- EndStep();
-
- return result;
- }
-
- [UseCaseStep("Generate C# code")]
- private string GenerateCSharpCode(
- CSharpAbstractSyntaxTree abstractSyntaxTree,
- string className,
- string libraryName,
- string namespaceName,
- string headerCodeRegion,
- string footerCodeRegion)
- {
- BeginStep();
- var codeGenerator = new CSharpCodeGenerator(
- className, libraryName, namespaceName, headerCodeRegion, footerCodeRegion);
- var result = codeGenerator.EmitCode(abstractSyntaxTree);
- EndStep();
-
- return result;
- }
-
- [UseCaseStep("Write C# code to file storage")]
- private void WriteCSharpCodeToFileStorage(
- string outputFilePath, string codeCSharp)
- {
- BeginStep();
- var outputDirectory = Path.GetDirectoryName(outputFilePath)!;
- if (string.IsNullOrEmpty(outputDirectory))
- {
- outputDirectory = AppContext.BaseDirectory;
- outputFilePath = Path.Combine(Environment.CurrentDirectory, outputFilePath);
- }
-
- if (!Directory.Exists(outputDirectory))
- {
- Directory.CreateDirectory(outputDirectory);
- }
-
- File.WriteAllText(outputFilePath, codeCSharp);
- Console.WriteLine(outputFilePath);
- EndStep();
- }
-}
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Domain/BuildTarget.cs b/src/cs/production/C2CS.Feature.BuildLibraryC/Domain/BuildTarget.cs
deleted file mode 100644
index 29e246f2..00000000
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Domain/BuildTarget.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-
-namespace C2CS.Feature.BuildLibraryC.Domain;
-
-public record BuildTarget
-{
- public RuntimeOperatingSystem OperatingSystem { get; init; }
-
- public ImmutableArray TargetArchitectures { get; init; }
-
- public bool IsEnabledCombineTargetArchitectures { get; init; }
-}
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Domain/DomainMapper.cs b/src/cs/production/C2CS.Feature.BuildLibraryC/Domain/DomainMapper.cs
deleted file mode 100644
index 87977c5e..00000000
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Domain/DomainMapper.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-using C2CS.Feature.BuildLibraryC.Data;
-
-namespace C2CS.Feature.BuildLibraryC.Domain;
-
-// NOTE: Maps from Data layer to Domain layer and/or vice-versa
-public static class DomainMapper
-{
- public static Input InputFrom(InputData data)
- {
- var buildTargets = BuildTargetsFrom(data.BuildTargets);
- var input = new Input(buildTargets);
-
- return input;
- }
-
- private static ImmutableArray BuildTargetsFrom(ImmutableArray? data)
- {
- if (data == null || data.Value.IsDefaultOrEmpty)
- {
- return ImmutableArray.Empty;
- }
-
- var builder = ImmutableArray.CreateBuilder();
- foreach (var buildTargetData in data)
- {
- if (buildTargetData == null)
- {
- continue;
- }
-
- var buildTarget = MapBuildTargetFrom(buildTargetData);
- builder.Add(buildTarget);
- }
-
- return builder.ToImmutable();
- }
-
- private static BuildTarget MapBuildTargetFrom(BuildTargetData data)
- {
- var operatingSystem = MapOperatingSystemFrom(data.OperatingSystem);
- var targetArchitectures = MapTargetArchitecturesFrom(operatingSystem, data.TargetArchitectures);
- var isEnabledCombineTargetArchitectures = MapIsEnabledCombineTargetArchitecturesFrom(operatingSystem, data.IsEnabledCombineArchitectures);
-
- var buildTarget = new BuildTarget
- {
- OperatingSystem = operatingSystem,
- TargetArchitectures = targetArchitectures,
- IsEnabledCombineTargetArchitectures = isEnabledCombineTargetArchitectures
- };
-
- return buildTarget;
- }
-
- private static RuntimeOperatingSystem MapOperatingSystemFrom(string? operatingSystemString)
- {
- if (!Enum.TryParse(operatingSystemString, out var operatingSystem) ||
- operatingSystem is RuntimeOperatingSystem.Unknown)
- {
- return Platform.HostOperatingSystem;
- }
-
- return operatingSystem;
- }
-
- private static ImmutableArray MapTargetArchitecturesFrom(
- RuntimeOperatingSystem operatingSystem,
- ImmutableArray? architectureStrings)
- {
- var results = ImmutableArray.CreateBuilder();
- if (architectureStrings == null)
- {
- results.Add(Platform.HostArchitecture);
- return results.ToImmutable();
- }
-
- var architecturesHashSetBuilder = ImmutableHashSet.CreateBuilder();
- foreach (var architectureString in architectureStrings)
- {
- if (string.IsNullOrEmpty(architectureString) ||
- !Enum.TryParse(architectureString, out var architecture) ||
- architecture is RuntimeArchitecture.Unknown)
- {
- continue;
- }
-
- architecturesHashSetBuilder.Add(architecture);
- }
-
- if (architecturesHashSetBuilder.Count == 0)
- {
- architecturesHashSetBuilder.Add(Platform.HostArchitecture);
- }
-
- var architecturesHashSet = architecturesHashSetBuilder.ToImmutable();
-
- switch (operatingSystem)
- {
- case RuntimeOperatingSystem.Windows:
- case RuntimeOperatingSystem.macOS:
- case RuntimeOperatingSystem.Linux:
- FilterDesktopArchitectures(architecturesHashSet, results);
- break;
- case RuntimeOperatingSystem.FreeBSD:
- case RuntimeOperatingSystem.Android:
- case RuntimeOperatingSystem.iOS:
- case RuntimeOperatingSystem.tvOS:
- case RuntimeOperatingSystem.Browser:
- case RuntimeOperatingSystem.PlayStation:
- case RuntimeOperatingSystem.Xbox:
- case RuntimeOperatingSystem.Switch:
- // TODO: Needs testing; requires hardware.
- throw new NotImplementedException();
- case RuntimeOperatingSystem.Unknown:
- throw new NotSupportedException();
- default:
- throw new ArgumentOutOfRangeException(nameof(operatingSystem), operatingSystem, null);
- }
-
- static void FilterDesktopArchitectures(
- ImmutableHashSet architectures,
- ImmutableArray.Builder builder)
- {
- if (architectures.Contains(RuntimeArchitecture.X64))
- {
- builder.Add(RuntimeArchitecture.X64);
- }
- else if (architectures.Contains(RuntimeArchitecture.X86))
- {
- builder.Add(RuntimeArchitecture.X86);
- }
- else if (architectures.Contains(RuntimeArchitecture.ARM64))
- {
- builder.Add(RuntimeArchitecture.ARM64);
- }
- else if (architectures.Contains(RuntimeArchitecture.ARM32))
- {
- builder.Add(RuntimeArchitecture.ARM32);
- }
- }
-
- return results.ToImmutable();
- }
-
- private static bool MapIsEnabledCombineTargetArchitecturesFrom(
- RuntimeOperatingSystem operatingSystem, bool? combineTargetArchitectures)
- {
- if (combineTargetArchitectures == null)
- {
- return false;
- }
-
- if (operatingSystem != RuntimeOperatingSystem.macOS &&
- operatingSystem != RuntimeOperatingSystem.iOS &&
- operatingSystem != RuntimeOperatingSystem.tvOS)
- {
- return false;
- }
-
- return combineTargetArchitectures.Value;
- }
-}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/C2CS.Feature.ExtractAbstractSyntaxTreeC.csproj b/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/C2CS.Feature.ExtractAbstractSyntaxTreeC.csproj
deleted file mode 100644
index 85450dae..00000000
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/C2CS.Feature.ExtractAbstractSyntaxTreeC.csproj
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
- net6.0
- enable
- enable
- $(NoWarn);CA1724
-
-
-
-
-
-
-
-
-
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Diagnostics/TypeFromIgnoredHeaderDiagnostic.cs b/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Diagnostics/TypeFromIgnoredHeaderDiagnostic.cs
deleted file mode 100644
index 34793545..00000000
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Diagnostics/TypeFromIgnoredHeaderDiagnostic.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Diagnostics;
-
-public class TypeFromIgnoredHeaderDiagnostic : Diagnostic
-{
- public TypeFromIgnoredHeaderDiagnostic(string typeName, string headerFilePath)
- : base(DiagnosticSeverity.Warning)
- {
- Summary =
- $"The type '{typeName}' belongs to the ignored header file '{headerFilePath}', but is used in the abstract syntax tree.";
- }
-}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Input.cs b/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Input.cs
deleted file mode 100644
index 0ac31ada..00000000
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Input.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC;
-
-public class Input
-{
- public string InputFilePath { get; }
-
- public string OutputFilePath { get; }
-
- public bool IsEnabledFindSdk { get; }
-
- public int MachineBitWidth { get; }
-
- public ImmutableArray IncludeDirectories { get; }
-
- public ImmutableArray ExcludedHeaderFiles { get; }
-
- public ImmutableArray OpaqueTypeNames { get; }
-
- public ImmutableArray FunctionNamesWhitelist { get; }
-
- public ImmutableArray ClangDefines { get; }
-
- public ImmutableArray ClangArguments { get; }
-
- public Input(
- string? inputFilePath,
- string? outputFilePath,
- bool? isEnabledFindSdk,
- int? machineBitWidth,
- ImmutableArray? includeDirectories,
- ImmutableArray? excludedHeaderFiles,
- ImmutableArray? opaqueTypeNames,
- ImmutableArray? functionNamesWhitelist,
- ImmutableArray? defines,
- ImmutableArray? clangArgs)
- {
- InputFilePath = VerifyInputFilePath(inputFilePath);
- OutputFilePath = VerifyOutputFilePath(outputFilePath);
- IsEnabledFindSdk = isEnabledFindSdk ?? true;
- MachineBitWidth = VerifyMachineBitWidth(machineBitWidth);
- IncludeDirectories = VerifyIncludeDirectories(includeDirectories, InputFilePath);
- ExcludedHeaderFiles = VerifyImmutableArray(excludedHeaderFiles);
- OpaqueTypeNames = VerifyImmutableArray(opaqueTypeNames);
- FunctionNamesWhitelist = VerifyImmutableArray(functionNamesWhitelist);
- ClangDefines = VerifyImmutableArray(defines);
- ClangArguments = VerifyImmutableArray(clangArgs);
- }
-
- private static string VerifyInputFilePath(string? inputFilePath)
- {
- if (string.IsNullOrEmpty(inputFilePath))
- {
- throw new ConfigurationException("The input file can not be null, empty, or whitespace.");
- }
-
- return Path.GetFullPath(inputFilePath);
- }
-
- private static string VerifyOutputFilePath(string? outputFilePath)
- {
- if (!string.IsNullOrEmpty(outputFilePath))
- {
- return Path.GetFullPath(outputFilePath);
- }
-
- var defaultFilePath = Path.GetTempFileName();
- return defaultFilePath;
- }
-
- private static int VerifyMachineBitWidth(int? machineBitWidth)
- {
- if (machineBitWidth == null)
- {
- return Platform.HostArchitecture switch
- {
- RuntimeArchitecture.ARM32 or RuntimeArchitecture.X86 => 32,
- RuntimeArchitecture.ARM64 or RuntimeArchitecture.X64 => 64,
- _ => throw new UseCaseException("Unknown runtime architecture.")
- };
- }
-
- return machineBitWidth.Value;
- }
-
- private static ImmutableArray VerifyIncludeDirectories(
- ImmutableArray? includeDirectories,
- string inputFilePath)
- {
- var result = VerifyImmutableArray(includeDirectories);
-
- if (result.IsDefaultOrEmpty)
- {
- var directoryPath = Path.GetDirectoryName(inputFilePath)!;
- if (string.IsNullOrEmpty(directoryPath))
- {
- directoryPath = Environment.CurrentDirectory;
- }
-
- result = new[]
- {
- Path.GetFullPath(directoryPath)
- }.ToImmutableArray();
- }
- else
- {
- result = result.Select(Path.GetFullPath).ToImmutableArray();
- }
-
- return result;
- }
-
- private static ImmutableArray VerifyImmutableArray(ImmutableArray? array)
- {
- if (array == null || array.Value.IsDefaultOrEmpty)
- {
- return ImmutableArray.Empty;
- }
-
- var result = array.Value
- .Where(x => !string.IsNullOrEmpty(x)).Cast().ToImmutableArray();
- return result;
- }
-}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/UseCase.cs b/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/UseCase.cs
deleted file mode 100644
index 1adb3b6c..00000000
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/UseCase.cs
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System.Collections.Immutable;
-using System.IO.Compression;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Data.Serialization;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Logic;
-using static bottlenoselabs.clang;
-
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC;
-
-public class UseCase : UseCaseHandler
-{
- private static string _clangNativeLibraryPath = null!;
-
- protected override void Execute(Input input, Output output)
- {
- Validate(input);
-
- SetupClang(Platform.HostOperatingSystem);
-
- var translationUnit = Parse(
- input.InputFilePath,
- input.IsEnabledFindSdk,
- input.IncludeDirectories,
- input.ClangDefines,
- input.MachineBitWidth,
- input.ClangArguments);
-
- var abstractSyntaxTreeC = Explore(
- translationUnit,
- input.IncludeDirectories,
- input.ExcludedHeaderFiles,
- input.OpaqueTypeNames,
- input.FunctionNamesWhitelist,
- input.MachineBitWidth);
-
- Write(
- input.OutputFilePath,
- abstractSyntaxTreeC);
- }
-
- [UseCaseStep("Setup Clang")]
- private void SetupClang(RuntimeOperatingSystem operatingSystem)
- {
- BeginStep();
-
- if (operatingSystem == RuntimeOperatingSystem.macOS)
- {
- _clangNativeLibraryPath = "/Library/Developer/CommandLineTools/usr/lib/libclang.dylib";
- if (!File.Exists(_clangNativeLibraryPath))
- {
- throw new ClangException(
- "Please install CommandLineTools for macOS. This will install `libclang.dylib`. Use the command `xcode-select --install`.");
- }
- }
- else if (operatingSystem == RuntimeOperatingSystem.Linux)
- {
- _clangNativeLibraryPath = Path.Combine(AppContext.BaseDirectory, "libclang.so");
- if (!File.Exists(_clangNativeLibraryPath))
- {
- DownloadLibClang("ubuntu.20.04-x64", _clangNativeLibraryPath);
- }
- }
- else if (operatingSystem == RuntimeOperatingSystem.Windows)
- {
- _clangNativeLibraryPath = Path.Combine(AppContext.BaseDirectory, "libclang.dll");
- if (!File.Exists(_clangNativeLibraryPath))
- {
- DownloadLibClang("win-x64", _clangNativeLibraryPath);
- }
- }
-
- EndStep();
-
- static void DownloadLibClang(string runtimeIdentifier, string target)
- {
- var zipFilePath = Path.Combine(AppContext.BaseDirectory, "libclang.zip");
- if (File.Exists(zipFilePath))
- {
- File.Delete(zipFilePath);
- }
-
- DownloadFile(
- $"https://www.nuget.org/api/v2/package/libclang.runtime.{runtimeIdentifier}",
- zipFilePath);
-
- var extractDirectory = Path.Combine(AppContext.BaseDirectory, "libclang");
- if (Directory.Exists(extractDirectory))
- {
- Directory.Delete(extractDirectory, true);
- }
-
- Directory.CreateDirectory(extractDirectory);
- ZipFile.ExtractToDirectory(zipFilePath, extractDirectory);
-
- var fileExtension = Path.GetExtension(target);
- File.Copy(
- Path.Combine(extractDirectory, $"runtimes/{runtimeIdentifier}/native/libclang{fileExtension}"),
- target);
- }
-
- static void DownloadFile(string url, string filePath)
- {
- using var client = new HttpClient();
- var uri = new Uri(url);
- using var response = client.GetStreamAsync(uri).Result;
- using var fileStream = new FileStream(filePath, FileMode.CreateNew);
- response.CopyToAsync(fileStream).Wait();
- }
-
- try
- {
- NativeLibrary.SetDllImportResolver(typeof(bottlenoselabs.clang).Assembly, ResolveClang);
- }
- catch (ArgumentException)
- {
- // already set; ignore
- }
- }
-
- private static IntPtr ResolveClang(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
- {
- if (!NativeLibrary.TryLoad(_clangNativeLibraryPath, out var handle))
- {
- throw new ClangException($"Could not load libclang: {_clangNativeLibraryPath}");
- }
-
- return handle;
- }
-
- private static void Validate(Input request)
- {
- if (!File.Exists(request.InputFilePath))
- {
- throw new UseCaseException($"The input file does not exist: `{request.InputFilePath}`.");
- }
-
- foreach (var includeDirectory in request.IncludeDirectories)
- {
- if (!Directory.Exists(includeDirectory))
- {
- throw new UseCaseException($"The include directory does not exist: `{includeDirectory}`.");
- }
- }
- }
-
- [UseCaseStep("Parse C code from disk")]
- private CXTranslationUnit Parse(
- string inputFilePath,
- bool automaticallyFindSoftwareDevelopmentKit,
- ImmutableArray includeDirectories,
- ImmutableArray defines,
- int bitness,
- ImmutableArray clangArguments)
- {
- BeginStep();
- var clangArgs = ClangArgumentsBuilder.Build(
- automaticallyFindSoftwareDevelopmentKit,
- includeDirectories,
- defines,
- bitness,
- clangArguments);
- var result = ClangTranslationUnitParser.Parse(inputFilePath, clangArgs);
- EndStep();
- return result;
- }
-
- [UseCaseStep("Extract C abstract syntax tree")]
- private CAbstractSyntaxTree Explore(
- CXTranslationUnit translationUnit,
- ImmutableArray includeDirectories,
- ImmutableArray excludedHeaderFiles,
- ImmutableArray opaqueTypeNames,
- ImmutableArray functionNamesWhitelist,
- int machineBitWidth)
- {
- BeginStep();
- var clangExplorer = new CTranslationUnitExplorer(
- Diagnostics, includeDirectories, excludedHeaderFiles, opaqueTypeNames, functionNamesWhitelist);
- var result = clangExplorer.AbstractSyntaxTree(translationUnit, machineBitWidth);
- EndStep();
- return result;
- }
-
- [UseCaseStep("Write C abstract syntax tree to disk")]
- private void Write(
- string outputFilePath, CAbstractSyntaxTree abstractSyntaxTree)
- {
- BeginStep();
- var outputDirectory = Path.GetDirectoryName(outputFilePath)!;
- if (string.IsNullOrEmpty(outputDirectory))
- {
- outputDirectory = AppContext.BaseDirectory;
- outputFilePath = Path.Combine(Environment.CurrentDirectory, outputFilePath);
- }
-
- if (!Directory.Exists(outputDirectory))
- {
- Directory.CreateDirectory(outputDirectory);
- }
-
- if (File.Exists(outputFilePath))
- {
- File.Delete(outputFilePath);
- }
-
- var serializerOptions = new JsonSerializerOptions
- {
- WriteIndented = true,
- Converters =
- {
- new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
- }
- };
- var serializerContext = new CJsonSerializerContext(serializerOptions);
- var fileContents = JsonSerializer.Serialize(abstractSyntaxTree, serializerContext.Options);
-
- // File.WriteAllText doesn't flush until process exits on macOS .NET 5 lol
- using var fileStream = new FileStream(outputFilePath, FileMode.OpenOrCreate);
- using var textWriter = new StreamWriter(fileStream);
- textWriter.Write(fileContents);
- textWriter.Close();
- fileStream.Close();
-
- Console.WriteLine(outputFilePath);
- EndStep();
- }
-}
diff --git a/src/cs/production/C2CS/C2CS.csproj b/src/cs/production/C2CS/C2CS.csproj
index 1d863c4d..6b319f0a 100644
--- a/src/cs/production/C2CS/C2CS.csproj
+++ b/src/cs/production/C2CS/C2CS.csproj
@@ -7,7 +7,13 @@
C2CS
false
en
- $(NoWarn);CA1724
+ $(NoWarn);CA1724;CA1812
+ win-x64;osx-x64;osx-arm64;linux-x64
+
+
+
+
+ false
@@ -21,18 +27,27 @@
+
+
+
+
+
+
+
+
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
diff --git a/src/cs/production/C2CS/C2CS.csproj.DotSettings b/src/cs/production/C2CS/C2CS.csproj.DotSettings
index 33a5359c..f4a900d7 100644
--- a/src/cs/production/C2CS/C2CS.csproj.DotSettings
+++ b/src/cs/production/C2CS/C2CS.csproj.DotSettings
@@ -16,7 +16,7 @@
True
True
True
- True
+ False
True
True
True
diff --git a/src/cs/production/C2CS/CommandLineArgumentsProvider.cs b/src/cs/production/C2CS/CommandLineArgumentsProvider.cs
new file mode 100644
index 00000000..1aea7ff1
--- /dev/null
+++ b/src/cs/production/C2CS/CommandLineArgumentsProvider.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+namespace C2CS;
+
+internal sealed class CommandLineArgumentsProvider
+{
+ public readonly string[] CommandLineArguments;
+
+ public CommandLineArgumentsProvider(string[] commandLineArguments)
+ {
+ CommandLineArguments = commandLineArguments;
+ }
+}
diff --git a/src/cs/production/C2CS/CommandLineInterface.cs b/src/cs/production/C2CS/CommandLineInterface.cs
new file mode 100644
index 00000000..53e81a09
--- /dev/null
+++ b/src/cs/production/C2CS/CommandLineInterface.cs
@@ -0,0 +1,106 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System;
+using System.CommandLine;
+using System.IO;
+using System.Text.Json;
+using C2CS.Data;
+using C2CS.Data.Serialization;
+using C2CS.Feature.ReadCodeC;
+using C2CS.Feature.WriteCodeCSharp;
+using Json.Schema;
+using Json.Schema.Generation;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace C2CS;
+
+internal class CommandLineInterface : RootCommand
+{
+ private readonly ConfigurationJsonSerializer _configurationJsonSerializer;
+ private readonly IServiceProvider _serviceProvider;
+
+ public CommandLineInterface(
+ ConfigurationJsonSerializer configurationJsonSerializer,
+ IServiceProvider serviceProvider)
+ : base("C2CS - C to C# bindings code generator.")
+ {
+ _configurationJsonSerializer = configurationJsonSerializer;
+ _serviceProvider = serviceProvider;
+
+ var configurationOption = new Option(
+ new[] { "--configurationFilePath", "-c" },
+ "File path of the configuration `.json` file.")
+ {
+ IsRequired = false
+ };
+
+ var abstractSyntaxTreeCommand = new Command(
+ "ast", "Dump the abstract syntax tree of a C `.h` file to one or more `.json` files per platform.");
+ abstractSyntaxTreeCommand.AddOption(configurationOption);
+ abstractSyntaxTreeCommand.SetHandler(HandleAbstractSyntaxTreesC, configurationOption);
+ AddCommand(abstractSyntaxTreeCommand);
+
+ var bindgenCSharpCommand = new Command(
+ "cs", "Generate a C# bindings `.cs` file from one or more C abstract syntax tree `.json` files per platform.");
+ bindgenCSharpCommand.AddOption(configurationOption);
+ bindgenCSharpCommand.SetHandler(HandleBindgenCSharp, configurationOption);
+ AddCommand(bindgenCSharpCommand);
+
+ var configurationGenerateSchemaCommand = new Command(
+ "schema", "Generate the `schema.json` file for the configuration in the working directory.");
+ configurationGenerateSchemaCommand.SetHandler(GenerateSchema);
+ this.SetHandler(Handle, configurationOption);
+ AddCommand(configurationGenerateSchemaCommand);
+ }
+
+ private void Handle(string configurationFilePath)
+ {
+ HandleAbstractSyntaxTreesC(configurationFilePath);
+ HandleBindgenCSharp(configurationFilePath);
+ }
+
+ private void HandleAbstractSyntaxTreesC(string configurationFilePath)
+ {
+ if (string.IsNullOrEmpty(configurationFilePath))
+ {
+ configurationFilePath = "config.json";
+ }
+
+ var configuration = _configurationJsonSerializer.Read(configurationFilePath);
+ var request = configuration.ReadC;
+ if (request == null)
+ {
+ return;
+ }
+
+ var useCase = _serviceProvider.GetService()!;
+ useCase.Execute(request);
+ }
+
+ private void HandleBindgenCSharp(string configurationFilePath)
+ {
+ if (string.IsNullOrEmpty(configurationFilePath))
+ {
+ configurationFilePath = "config.json";
+ }
+
+ var configuration = _configurationJsonSerializer.Read(configurationFilePath);
+ var request = configuration.WriteCSharp;
+ if (request == null)
+ {
+ return;
+ }
+
+ var useCase = _serviceProvider.GetService()!;
+ useCase.Execute(request);
+ }
+
+ private static void GenerateSchema()
+ {
+ var schemaBuilder = new JsonSchemaBuilder().FromType();
+ var schema = schemaBuilder.Build();
+ var json = JsonSerializer.Serialize(schema);
+ File.WriteAllText("schema.json", json);
+ }
+}
diff --git a/src/cs/production/C2CS/CommandLineService.cs b/src/cs/production/C2CS/CommandLineService.cs
new file mode 100644
index 00000000..648610f7
--- /dev/null
+++ b/src/cs/production/C2CS/CommandLineService.cs
@@ -0,0 +1,45 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System;
+using System.CommandLine;
+using System.CommandLine.Help;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Hosting;
+
+namespace C2CS;
+
+internal sealed class CommandLineService : IHostedService
+{
+ private readonly IApplicationLifetime _applicationLifetime;
+ private readonly string[] _commandLineArguments;
+ private readonly RootCommand _rootCommand;
+
+ public CommandLineService(
+ IApplicationLifetime applicationLifetime,
+ CommandLineArgumentsProvider commandLineArgumentsProvider,
+ RootCommand command)
+ {
+ _applicationLifetime = applicationLifetime;
+ _commandLineArguments = commandLineArgumentsProvider.CommandLineArguments;
+ _rootCommand = command;
+ }
+
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ _applicationLifetime.ApplicationStarted.Register(() => Task.Run(Main, cancellationToken));
+ return Task.CompletedTask;
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
+ }
+
+ private void Main()
+ {
+ Environment.ExitCode = _rootCommand.Invoke(_commandLineArguments);
+ _applicationLifetime.StopApplication();
+ }
+}
diff --git a/src/cs/production/C2CS/Configuration.cs b/src/cs/production/C2CS/Configuration.cs
deleted file mode 100644
index c71f5d73..00000000
--- a/src/cs/production/C2CS/Configuration.cs
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.IO;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-using C2CS.Feature.BindgenCSharp.Data;
-
-namespace C2CS;
-
-// NOTE: Properties are required for System.Text.Json serialization
-// NOTE: This class is considered un-sanitized input; all strings and other types could be null.
-public class Configuration
-{
- ///
- /// Path of the input `.h` header file.
- ///
- public string? InputFilePath { get; set; }
-
- ///
- /// Path of the output C# `.cs` file. If not specified, defaults to a file path using the current directory, a
- /// file name without extension that matches the , and a `.cs` file name extension.
- ///
- public string? OutputFilePath { get; set; }
-
- ///
- /// Path of the intermediate output abstract syntax tree `.json` file. If not specified, defaults to a random
- /// temporary file.
- ///
- public string? AbstractSyntaxTreeOutputFilePath { get; set; }
-
- ///
- /// The name of the dynamic link library (without the file extension) used for platform invoke (P/Invoke) with
- /// C#. If not specified, the library name is the same as the name of the without
- /// the directory name and without the file extension.
- ///
- public string? LibraryName { get; set; }
-
- ///
- /// The name of the namespace to be used for the C# static class. If not specified, the namespace is the same as the
- /// .
- ///
- public string? NamespaceName { get; set; }
-
- ///
- /// The name of the C# static class. If not specified, the class name is the same as the
- /// .
- ///
- public string? ClassName { get; set; }
-
- ///
- /// Path of the text file which to add the file's contents to the top of the C# file. Useful for comments, extra
- /// namespace using statements, or additional code that needs to be added to the generated C# file.
- ///
- public string? HeaderCodeRegionFilePath { get; set; }
-
- ///
- /// Path of the text file which to add the file's contents to the bottom of the C# file. Useful for comments or
- /// additional code that needs to be added to the generated C# file.
- ///
- public string? FooterCodeRegionFilePath { get; set; }
-
- ///
- /// Pairs of strings for re-mapping type names. Each pair has source name and a target name. The source name may
- /// be found when parsing C code and get mapped to the target name when generating C# code. Does not change the
- /// type's bit layout.
- ///
- public ImmutableArray? MappedTypeNames { get; set; }
-
- ///
- /// Determines whether the software development kit (SDK) for C/C++ is attempted to be found. Default is
- /// true. If true, the C/C++ header files for the current operating system are attempted to be
- /// found. In such a case, if the C/C++ header files can not be found, then an error is generated which halts
- /// the program. If false, the C/C++ header files will likely be missing causing Clang to generate
- /// parsing errors which also halts the program. In such a case, the missing C/C++ header files can be supplied
- /// to Clang using such as "-isystemPATH/TO/SYSTEM/HEADER/DIRECTORY".
- ///
- public bool? IsEnabledFindSdk { get; set; } = true;
-
- ///
- /// The bit width of the computer architecture to use when parsing C code. Default is null. If
- /// null, the bit width of host operating system's computer architecture is used. E.g. the default for
- /// x64 Windows is `64`. Possible values are null, 32 where pointers are 4 bytes, or 64
- /// where pointers are 8 bytes.
- ///
- public int? MachineBitWidth { get; set; }
-
- ///
- /// Search directory paths to use for `#include` usages when parsing C code. If null, uses the
- /// directory path of .
- ///
- public ImmutableArray? IncludeDirectories { get; set; }
-
- ///
- /// Object-like macros to use when parsing C code.
- ///
- public ImmutableArray? Defines { get; set; }
-
- ///
- /// C header file names to exclude. File names are relative to .
- ///
- public ImmutableArray? ExcludedHeaderFiles { get; set; }
-
- ///
- /// Type names that may be found when parsing C code that will be ignored when generating C# code.
- /// Types are ignored after mapping type names using .
- ///
- public ImmutableArray? IgnoredTypeNames { get; set; }
-
- ///
- /// The C function names to explicitly include when parsing C code. Default is null. If null,
- /// no white list applies to which all C function names that are found are eligible for C# code generation.
- /// Note that C function names which are excluded also exclude any transitive types.
- ///
- public ImmutableArray? FunctionNamesWhiteList { get; set; }
-
- ///
- /// Type names that may be found when parsing C code that will be interpreted as opaque types. Opaque types are
- /// often used with a pointer to hide the information about the bit layout behind the pointer.
- ///
- public ImmutableArray? OpaqueTypeNames { get; set; }
-
- ///
- /// Additional Clang arguments to use when parsing C code.
- ///
- public ImmutableArray? ClangArguments { get; set; }
-
- public static Configuration GetFrom(IReadOnlyList? args)
- {
- var argsCount = args?.Count ?? 0;
- var configurationFilePath = argsCount switch
- {
- 1 => args![0],
- 0 => Path.Combine(Environment.CurrentDirectory, "config.json"),
- _ => throw new InvalidOperationException(
- "Unsupported number of arguments. Please specify zero arguments or one argument with the file path of the configuration `.json` file.")
- };
-
- try
- {
- var fileContents = File.ReadAllText(configurationFilePath);
- var jsonSerializerOptions = new JsonSerializerOptions
- {
- WriteIndented = true,
- PropertyNameCaseInsensitive = true,
- DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
-
- Converters =
- {
- new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
- }
- };
- var serializerContext = new C2CS.ConfigurationSerializerContext(jsonSerializerOptions);
- var configuration = JsonSerializer.Deserialize(fileContents, serializerContext.Configuration)!;
- return configuration;
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- throw;
- }
- }
-}
diff --git a/src/cs/production/C2CS/Data/Configuration.cs b/src/cs/production/C2CS/Data/Configuration.cs
new file mode 100644
index 00000000..97e7f682
--- /dev/null
+++ b/src/cs/production/C2CS/Data/Configuration.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.Text.Json.Serialization;
+using C2CS.Feature.ReadCodeC.Data;
+using C2CS.Feature.WriteCodeCSharp.Data;
+using JetBrains.Annotations;
+
+namespace C2CS.Data;
+
+// NOTE: Properties are required for System.Text.Json serialization
+// NOTE: This class is considered un-sanitized input; all strings and other types could be null.
+// NOTE: This class must have a unique name across namespaces for usage in System.Text.Json source generators.
+[PublicAPI]
+public sealed class Configuration
+{
+ [JsonPropertyName("directory")]
+ [Json.Schema.Generation.Description("Path of the input and output abstract syntax tree directory. By default, the directory will be used to write a `.json` file for each target platform's abstract syntax tree that has been extracted. By default, the same abstract syntax tree `.json` files will then be read when generating C# code.")]
+ public string? InputOutputFileDirectory { get; set; }
+
+ [JsonPropertyName("ast")]
+ [Json.Schema.Generation.Description("The configuration for reading the `.h` C header file.")]
+ public ReadCodeCConfiguration? ReadC { get; set; }
+
+ [JsonPropertyName("cs")]
+ [Json.Schema.Generation.Description("The configuration for writing the `.cs` C# source code file.")]
+ public WriteCodeCSharpConfiguration? WriteCSharp { get; set; }
+}
diff --git a/src/cs/production/C2CS/Data/Serialization/ConfigurationJsonSerializer.cs b/src/cs/production/C2CS/Data/Serialization/ConfigurationJsonSerializer.cs
new file mode 100644
index 00000000..ed0e2941
--- /dev/null
+++ b/src/cs/production/C2CS/Data/Serialization/ConfigurationJsonSerializer.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System;
+using System.IO.Abstractions;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using C2CS.Feature.ReadCodeC.Data;
+using C2CS.Feature.WriteCodeCSharp.Data;
+using C2CS.Foundation.Data.Serialization;
+using Microsoft.Extensions.Logging;
+
+namespace C2CS.Data.Serialization;
+
+public sealed class ConfigurationJsonSerializer
+{
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
+ private readonly ConfigurationSerializerContext _serializerContext;
+
+ public ConfigurationJsonSerializer(ILogger logger, IFileSystem fileSystem)
+ {
+ _logger = logger;
+ _fileSystem = fileSystem;
+
+ var jsonSerializerOptions = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ PropertyNameCaseInsensitive = true,
+ PropertyNamingPolicy = SnakeCaseNamingPolicy.Instance,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
+ Converters =
+ {
+ new JsonStringEnumConverter(SnakeCaseNamingPolicy.Instance)
+ }
+ };
+ _serializerContext = new ConfigurationSerializerContext(jsonSerializerOptions);
+ }
+
+ public Configuration Read(string filePath)
+ {
+ var fullFilePath = _fileSystem.Path.GetFullPath(filePath);
+
+ try
+ {
+ var fileContents = _fileSystem.File.ReadAllText(fullFilePath);
+ var configuration = JsonSerializer.Deserialize(fileContents, _serializerContext.Configuration)!;
+
+ Polyfill(configuration);
+
+ _logger.ConfigurationLoadSuccess(fullFilePath);
+ return configuration;
+ }
+ catch (Exception e)
+ {
+ _logger.ConfigurationLoadFailure(fullFilePath, e);
+ throw;
+ }
+ }
+
+ private static void Polyfill(Configuration configuration)
+ {
+ var requestExtractC = configuration.ReadC;
+ if (requestExtractC?.ConfigurationAbstractSyntaxTrees != null)
+ {
+ foreach (var (_, extractAbstractSyntaxTreeC) in requestExtractC.ConfigurationAbstractSyntaxTrees)
+ {
+ if (extractAbstractSyntaxTreeC != null)
+ {
+ PolyfillExtractAbstractSyntaxTreeC(configuration, extractAbstractSyntaxTreeC);
+ }
+ }
+ }
+
+ var requestBindgenCSharp = configuration.WriteCSharp;
+ if (requestBindgenCSharp != null)
+ {
+ PolyfillBindgenCSharp(configuration, requestBindgenCSharp);
+ }
+ }
+
+ private static void PolyfillExtractAbstractSyntaxTreeC(
+ Configuration configuration, ReadCodeCConfigurationAbstractSyntaxTree extract)
+ {
+ if (string.IsNullOrEmpty(extract.OutputFileDirectory))
+ {
+ extract.OutputFileDirectory = configuration.InputOutputFileDirectory;
+ }
+ }
+
+ private static void PolyfillBindgenCSharp(Configuration configuration, WriteCodeCSharpConfiguration write)
+ {
+ if (string.IsNullOrEmpty(write.InputFileDirectory))
+ {
+ write.InputFileDirectory = configuration.InputOutputFileDirectory;
+ }
+ }
+}
diff --git a/src/cs/production/C2CS/ConfigurationSerializerContext.cs b/src/cs/production/C2CS/Data/Serialization/ConfigurationSerializerContext.cs
similarity index 83%
rename from src/cs/production/C2CS/ConfigurationSerializerContext.cs
rename to src/cs/production/C2CS/Data/Serialization/ConfigurationSerializerContext.cs
index 0c55d293..bdae56f6 100644
--- a/src/cs/production/C2CS/ConfigurationSerializerContext.cs
+++ b/src/cs/production/C2CS/Data/Serialization/ConfigurationSerializerContext.cs
@@ -3,7 +3,7 @@
using System.Text.Json.Serialization;
-namespace C2CS;
+namespace C2CS.Data.Serialization;
[JsonSourceGenerationOptions(
WriteIndented = true,
@@ -11,6 +11,6 @@ namespace C2CS;
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
GenerationMode = JsonSourceGenerationMode.Metadata)]
[JsonSerializable(typeof(Configuration))]
-internal partial class ConfigurationSerializerContext : JsonSerializerContext
+public partial class ConfigurationSerializerContext : JsonSerializerContext
{
}
diff --git a/src/cs/production/C2CS/Data/Serialization/Logging.cs b/src/cs/production/C2CS/Data/Serialization/Logging.cs
new file mode 100644
index 00000000..5b403138
--- /dev/null
+++ b/src/cs/production/C2CS/Data/Serialization/Logging.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System;
+using C2CS.Foundation;
+using C2CS.Foundation.Logging;
+using Microsoft.Extensions.Logging;
+
+namespace C2CS.Data.Serialization;
+
+public static class Logging
+{
+ private static readonly Action ActionConfigurationSuccess = LoggerMessage.Define(
+ LogLevel.Information,
+ LoggingEventRegistry.CreateEventIdentifier("Configuration load: success."),
+ "Configuration load: Success. Path: {FilePath}.");
+
+ private static readonly Action ActionConfigurationFailure = LoggerMessage.Define(
+ LogLevel.Information,
+ LoggingEventRegistry.CreateEventIdentifier("Configuration load: failure."),
+ "Configuration load. Failed. Path: {FilePath}.");
+
+ public static void ConfigurationLoadSuccess(this ILogger logger, string filePath)
+ {
+ ActionConfigurationSuccess(logger, filePath, null!);
+ }
+
+ public static void ConfigurationLoadFailure(this ILogger logger, string filePath, Exception exception)
+ {
+ ActionConfigurationFailure(logger, filePath, exception);
+ }
+}
diff --git a/src/cs/production/C2CS/Program.cs b/src/cs/production/C2CS/Program.cs
index 5e791d64..7c726bad 100644
--- a/src/cs/production/C2CS/Program.cs
+++ b/src/cs/production/C2CS/Program.cs
@@ -2,74 +2,16 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
using System;
-using System.Linq;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC;
+using Microsoft.Extensions.Hosting;
namespace C2CS;
public static class Program
{
- public static int Main(string[]? args = null)
+ public static int Main(string[] args)
{
- if (args != null && args.Length == 2 && args[0] == "build")
- {
- return Feature.BuildLibraryC.Program.Main(args.Skip(1).ToArray());
- }
- else
- {
- var configuration = Configuration.GetFrom(args);
- return EntryPoint(configuration);
- }
- }
-
- // ReSharper disable once MemberCanBePrivate.Global
- public static int EntryPoint(Configuration configuration)
- {
- var jsonFilePath = ExtractAbstractSyntaxTreeC(configuration);
- BindgenCSharp(jsonFilePath, configuration);
+ using var host = Startup.CreateHost(args);
+ host.Run();
return Environment.ExitCode;
}
-
- private static string ExtractAbstractSyntaxTreeC(Configuration c)
- {
- var request = new Feature.ExtractAbstractSyntaxTreeC.Input(
- c.InputFilePath,
- c.AbstractSyntaxTreeOutputFilePath,
- c.IsEnabledFindSdk,
- c.MachineBitWidth,
- c.IncludeDirectories,
- c.ExcludedHeaderFiles,
- c.OpaqueTypeNames,
- c.FunctionNamesWhiteList,
- c.Defines,
- c.ClangArguments);
- var useCase = new UseCase();
- var response = useCase.Execute(request);
- if (response.Status == UseCaseOutputStatus.Failure)
- {
- Environment.Exit(1);
- }
-
- return request.OutputFilePath;
- }
-
- private static void BindgenCSharp(string inputFilePath, Configuration c)
- {
- var request = new Feature.BindgenCSharp.Input(
- inputFilePath,
- c.OutputFilePath,
- c.LibraryName,
- c.NamespaceName,
- c.ClassName,
- c.MappedTypeNames,
- c.IgnoredTypeNames,
- c.HeaderCodeRegionFilePath,
- c.FooterCodeRegionFilePath);
- var useCase = new Feature.BindgenCSharp.UseCase();
- var response = useCase.Execute(request);
- if (response.Status == UseCaseOutputStatus.Failure)
- {
- Environment.Exit(1);
- }
- }
}
diff --git a/src/cs/production/C2CS/Startup.cs b/src/cs/production/C2CS/Startup.cs
new file mode 100644
index 00000000..2c84db81
--- /dev/null
+++ b/src/cs/production/C2CS/Startup.cs
@@ -0,0 +1,59 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System;
+using System.CommandLine;
+using System.IO.Abstractions;
+using C2CS.Data.Serialization;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Console;
+
+namespace C2CS;
+
+public static class Startup
+{
+ public static IHost CreateHost(string[] args)
+ {
+ return new HostBuilder()
+ .UseConsoleLifetime()
+ .BuildHostCommon(args)
+ .Build();
+ }
+
+ public static IHostBuilder BuildHostCommon(this IHostBuilder builder, string[]? args = null)
+ {
+ return builder
+ .ConfigureServices(services => ConfigureServices(services, args))
+ .UseServiceProviderFactory(new DefaultServiceProviderFactory(new ServiceProviderOptions
+ {
+ ValidateScopes = true,
+ ValidateOnBuild = true
+ }));
+ }
+
+ private static void ConfigureServices(IServiceCollection services, string[]? args)
+ {
+ services.AddSingleton();
+ services.AddSingleton(new CommandLineArgumentsProvider(args ?? Environment.GetCommandLineArgs()));
+ services.AddLogging(x =>
+ x.AddSimpleConsole(options =>
+ {
+ options.ColorBehavior = LoggerColorBehavior.Enabled;
+ options.SingleLine = true;
+ options.IncludeScopes = true;
+ options.UseUtcTimestamp = true;
+ options.TimestampFormat = "yyyy-dd-MM HH:mm:ss ";
+ }));
+ services.AddSingleton(x =>
+ x.GetRequiredService().CreateLogger(string.Empty));
+ services.AddHostedService();
+ services.AddSingleton();
+ services.AddSingleton();
+
+ Feature.ReadCodeC.Startup.ConfigureServices(services);
+ Feature.WriteCodeCSharp.Startup.ConfigureServices(services);
+ Feature.BuildLibraryC.Startup.ConfigureServices(services);
+ }
+}
diff --git a/src/cs/production/Directory.Build.props b/src/cs/production/Directory.Build.props
index e2be5638..0b794275 100644
--- a/src/cs/production/Directory.Build.props
+++ b/src/cs/production/Directory.Build.props
@@ -9,7 +9,7 @@
latest
-
+
true
true
diff --git a/src/cs/production/clang-c/clang-c.csproj b/src/cs/production/clang-c/clang-c.csproj
deleted file mode 100644
index 910f3275..00000000
--- a/src/cs/production/clang-c/clang-c.csproj
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- net6.0
- Exe
-
-
-
-
-
-
-
-
-
- PreserveNewest
-
-
-
-
diff --git a/src/cs/production/clang-cs/ClangLocation.cs b/src/cs/production/clang-cs/ClangLocation.cs
deleted file mode 100644
index 80d09101..00000000
--- a/src/cs/production/clang-cs/ClangLocation.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System;
-using System.Text.Json.Serialization;
-
-// NOTE: Properties are required for System.Text.Json serialization
-public struct ClangLocation : IComparable, IEquatable
-{
- [JsonPropertyName("fileName")]
- public string FileName { get; set; }
-
- [JsonPropertyName("filePath")]
- public string FilePath { get; set; }
-
- [JsonPropertyName("line")]
- public int LineNumber { get; set; }
-
- [JsonPropertyName("column")]
- public int LineColumn { get; set; }
-
- [JsonPropertyName("isBuiltin")]
- public bool IsBuiltin { get; set; }
-
- public override string ToString()
- {
- if (LineNumber == 0 && LineColumn == 0)
- {
- return $"{FileName}";
- }
-
- return string.IsNullOrEmpty(FilePath) || FilePath == FileName
- ? $"{FileName}:{LineNumber}:{LineColumn}"
- : $"{FileName}:{LineNumber}:{LineColumn} ({FilePath})";
- }
-
- public bool Equals(ClangLocation other)
- {
- return FilePath == other.FilePath && LineNumber == other.LineNumber;
- }
-
- public override bool Equals(object? obj)
- {
- return obj is ClangLocation other && Equals(other);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(FilePath, LineNumber, LineColumn);
- }
-
- public int CompareTo(ClangLocation other)
- {
- // ReSharper disable once JoinDeclarationAndInitializer
- int result;
-
- result = string.Compare(FileName, other.FileName, StringComparison.Ordinal);
- // ReSharper disable once ConvertIfStatementToReturnStatement
- if (result != 0)
- {
- return result;
- }
-
- result = LineNumber.CompareTo(other.LineNumber);
-
- return result;
- }
-
- public static bool operator ==(ClangLocation first, ClangLocation second)
- {
- return first.Equals(second);
- }
-
- public static bool operator !=(ClangLocation first, ClangLocation second)
- {
- return !(first == second);
- }
-
- public static bool operator <(ClangLocation first, ClangLocation second)
- {
- return first.CompareTo(second) < 0;
- }
-
- public static bool operator >(ClangLocation first, ClangLocation second)
- {
- return first.CompareTo(second) > 0;
- }
-
- public static bool operator >=(ClangLocation first, ClangLocation second)
- {
- return first.CompareTo(second) >= 0;
- }
-
- public static bool operator <=(ClangLocation first, ClangLocation second)
- {
- return first.CompareTo(second) <= 0;
- }
-}
diff --git a/src/cs/production/clang-cs/ClangTranslationUnitParser.cs b/src/cs/production/clang-cs/ClangTranslationUnitParser.cs
deleted file mode 100644
index b4d71069..00000000
--- a/src/cs/production/clang-cs/ClangTranslationUnitParser.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-
-using System;
-using System.Collections.Immutable;
-using static bottlenoselabs.clang;
-
-public static class ClangTranslationUnitParser
-{
- public static CXTranslationUnit Parse(
- string headerFilePath,
- ImmutableArray clangArgs)
- {
- var clangArgsConcat = string.Join(" ", clangArgs);
- Console.WriteLine($"libclang: Parsing '{headerFilePath}' with the following arguments...");
- Console.WriteLine($"\t{clangArgsConcat}");
-
- if (!TryParseTranslationUnit(headerFilePath, clangArgs, out var translationUnit))
- {
- throw new ClangException("libclang failed.");
- }
-
- var diagnostics = GetCompilationDiagnostics(translationUnit);
- if (diagnostics.IsDefaultOrEmpty)
- {
- return translationUnit;
- }
-
- var defaultDisplayOptions = clang_defaultDiagnosticDisplayOptions();
- Console.Error.WriteLine("Clang diagnostics:");
- var hasErrors = false;
- foreach (var diagnostic in diagnostics)
- {
- Console.Error.Write("\t");
- var clangString = clang_formatDiagnostic(diagnostic, defaultDisplayOptions);
- var diagnosticStringC = clang_getCString(clangString);
- var diagnosticString = Runtime.CStrings.String(diagnosticStringC);
- Console.Error.WriteLine(diagnosticString);
-
- var severity = clang_getDiagnosticSeverity(diagnostic);
- if (severity == CXDiagnosticSeverity.CXDiagnostic_Error ||
- severity == CXDiagnosticSeverity.CXDiagnostic_Fatal)
- {
- hasErrors = true;
- }
- }
-
- if (hasErrors)
- {
- throw new ClangException("Clang parsing errors.");
- }
-
- return translationUnit;
- }
-
- private static unsafe bool TryParseTranslationUnit(
- string filePath,
- ImmutableArray commandLineArgs,
- out CXTranslationUnit translationUnit)
- {
- // ReSharper disable BitwiseOperatorOnEnumWithoutFlags
- const uint options = 0x00001000 | // CXTranslationUnit_IncludeAttributedTypes
- 0x00004000 | // CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles
- 0x00000040 | // CXTranslationUnit_SkipFunctionBodies
- 0x1 | // CXTranslationUnit_DetailedPreprocessingRecord
- 0x0;
-
- var index = clang_createIndex(0, 0);
- var cSourceFilePath = Runtime.CStrings.CString(filePath);
- var cCommandLineArgs = Runtime.CStrings.CStringArray(commandLineArgs.AsSpan());
-
- CXErrorCode errorCode;
- fixed (CXTranslationUnit* translationUnitPointer = &translationUnit)
- {
- errorCode = clang_parseTranslationUnit2(
- index,
- cSourceFilePath,
- cCommandLineArgs,
- commandLineArgs.Length,
- (CXUnsavedFile*)IntPtr.Zero,
- 0,
- options,
- translationUnitPointer);
- }
-
- var result = errorCode == CXErrorCode.CXError_Success;
- return result;
- }
-
- private static ImmutableArray GetCompilationDiagnostics(CXTranslationUnit translationUnit)
- {
- var diagnosticsCount = (int)clang_getNumDiagnostics(translationUnit);
- var builder = ImmutableArray.CreateBuilder(diagnosticsCount);
-
- for (uint i = 0; i < diagnosticsCount; ++i)
- {
- var diagnostic = clang_getDiagnostic(translationUnit, i);
- builder.Add(diagnostic);
- }
-
- return builder.ToImmutable();
- }
-}
diff --git a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseOutputStatus.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryConfiguration.cs
similarity index 62%
rename from src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseOutputStatus.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryConfiguration.cs
index dab3716f..d005495d 100644
--- a/src/cs/production/C2CS.Common/Foundation/UseCases/UseCaseOutputStatus.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryConfiguration.cs
@@ -1,10 +1,10 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-namespace C2CS;
+using C2CS.Foundation.UseCases;
-public enum UseCaseOutputStatus
+namespace C2CS.Feature.BuildLibraryC;
+
+public class BuildLibraryConfiguration : UseCaseConfiguration
{
- Failure,
- Success
}
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Input.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryInput.cs
similarity index 66%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/Input.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryInput.cs
index 94b9e817..7549a827 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Input.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryInput.cs
@@ -1,24 +1,24 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-using System.Collections.Immutable;
using System.Text.Json;
using System.Text.Json.Serialization;
-using C2CS.Feature.BuildLibraryC.Data.Serialization;
-using C2CS.Feature.BuildLibraryC.Domain;
+using C2CS.Feature.BuildLibraryC.Data;
+using C2CS.Foundation;
+using JsonSerializerContext = C2CS.Feature.BuildLibraryC.Data.Serialization.JsonSerializerContext;
namespace C2CS.Feature.BuildLibraryC;
-public class Input
+public class BuildLibraryInput
{
- public ImmutableArray BuildTargets { get; }
+ public BuildProject Project { get; }
- public Input(ImmutableArray buildTargets)
+ public BuildLibraryInput(BuildProject project)
{
- BuildTargets = buildTargets;
+ Project = project;
}
- public static Input GetFrom(IReadOnlyList? args)
+ public static BuildLibraryInput GetFrom(IReadOnlyList? args)
{
var argsCount = args?.Count ?? 0;
@@ -44,9 +44,9 @@ public static Input GetFrom(IReadOnlyList? args)
}
};
- var serializerContext = new InputDataSerializerContext(jsonSerializerOptions);
- var data = JsonSerializer.Deserialize(fileContents, serializerContext.InputData)!;
- var input = DomainMapper.InputFrom(data);
+ var serializerContext = new JsonSerializerContext(jsonSerializerOptions);
+ var buildProject = JsonSerializer.Deserialize(fileContents, serializerContext.BuildProject)!;
+ var input = new BuildLibraryInput(buildProject);
return input;
}
catch (Exception e)
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Output.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryOutput.cs
similarity index 72%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/Output.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryOutput.cs
index d1b4b9df..d124c0a6 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Output.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryOutput.cs
@@ -2,11 +2,12 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
using System.Collections.Immutable;
-using C2CS.Feature.BuildLibraryC.Domain;
+using C2CS.Feature.BuildLibraryC.Data;
+using C2CS.Foundation.UseCases;
namespace C2CS.Feature.BuildLibraryC;
-public class Output : UseCaseOutput
+public class BuildLibraryOutput : UseCaseOutput
{
public ImmutableArray BuildTargetResults { get; }
}
diff --git a/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryUseCase.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryUseCase.cs
new file mode 100644
index 00000000..cf5912aa
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryUseCase.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using C2CS.Foundation.UseCases;
+using Microsoft.Extensions.Logging;
+
+namespace C2CS.Feature.BuildLibraryC;
+
+public class BuildLibraryUseCase : UseCase
+{
+ public override string Name => "Build C library";
+
+ public BuildLibraryUseCase(ILogger logger, IServiceProvider services, BuildLibraryValidator validator)
+ : base(logger, services, validator)
+ {
+ }
+
+ protected override void Execute(BuildLibraryInput input, BuildLibraryOutput output)
+ {
+ var targets = input.Project.Targets;
+ if (targets.IsDefaultOrEmpty)
+ {
+ return;
+ }
+
+ foreach (var buildTarget in input.Project.Targets)
+ {
+ Console.WriteLine(buildTarget);
+ }
+ }
+}
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Program.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryValidator.cs
similarity index 50%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/Program.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryValidator.cs
index 4e1857f6..9722364f 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Program.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/BuildLibraryValidator.cs
@@ -1,15 +1,14 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using C2CS.Foundation.UseCases;
+
namespace C2CS.Feature.BuildLibraryC;
-public static class Program
+public class BuildLibraryValidator : UseCaseValidator
{
- public static int Main(string[]? args = null)
+ public override BuildLibraryInput Validate(BuildLibraryConfiguration configuration)
{
- var input = Input.GetFrom(args);
- var handler = new Handler();
- var output = handler.Execute(input);
- return output.Status == UseCaseOutputStatus.Success ? 0 : 1;
+ throw new NotImplementedException();
}
}
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj b/src/cs/production/features/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj
similarity index 53%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj
index 420c789c..08c76e90 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj
@@ -5,14 +5,19 @@
net6.0
enable
enable
- Exe
C2CS.Feature.BuildLibraryC
$(NoWarn);CA1724
-
-
+
+
+
+
+
+
+
+
diff --git a/src/cs/production/C2CS.Common/C2CS.Common.csproj.DotSettings b/src/cs/production/features/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj.DotSettings
similarity index 55%
rename from src/cs/production/C2CS.Common/C2CS.Common.csproj.DotSettings
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj.DotSettings
index 553cc259..159773b2 100644
--- a/src/cs/production/C2CS.Common/C2CS.Common.csproj.DotSettings
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/C2CS.Feature.BuildLibraryC.csproj.DotSettings
@@ -1,4 +1,5 @@
- True
- True
- True
\ No newline at end of file
+ True
+ False
+ True
+ False
\ No newline at end of file
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Data/BuildTargetData.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProject.cs
similarity index 68%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/Data/BuildTargetData.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProject.cs
index 4748a819..b2d8f181 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Data/BuildTargetData.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProject.cs
@@ -7,11 +7,9 @@ namespace C2CS.Feature.BuildLibraryC.Data;
// NOTE: Properties are required for System.Text.Json serialization
// NOTE: This class is considered un-sanitized input; all strings and other types could be null.
-public class BuildTargetData
+public abstract class BuildProject
{
- public string? OperatingSystem { get; set; }
+ public BuildProjectType Type { get; set; }
- public ImmutableArray? TargetArchitectures { get; set; }
-
- public bool? IsEnabledCombineArchitectures { get; set; }
+ public ImmutableArray Targets { get; set; }
}
diff --git a/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProjectCMake.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProjectCMake.cs
new file mode 100644
index 00000000..8aceee89
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProjectCMake.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+namespace C2CS.Feature.BuildLibraryC.Data;
+
+// NOTE: Properties are required for System.Text.Json serialization
+// NOTE: This class is considered un-sanitized input; all strings and other types could be null.
+public class BuildProjectCMake : BuildProject
+{
+ public string CMakeListsDirectoryPath { get; set; } = string.Empty;
+
+ public BuildProjectCMake()
+ {
+ Type = BuildProjectType.CMake;
+ }
+}
diff --git a/src/cs/production/C2CS.Feature.BindgenCSharp/Output.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProjectType.cs
similarity index 69%
rename from src/cs/production/C2CS.Feature.BindgenCSharp/Output.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProjectType.cs
index 108d6d4b..90aca7c5 100644
--- a/src/cs/production/C2CS.Feature.BindgenCSharp/Output.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildProjectType.cs
@@ -1,8 +1,10 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-namespace C2CS.Feature.BindgenCSharp;
+namespace C2CS.Feature.BuildLibraryC.Data;
-public class Output : UseCaseOutput
+public enum BuildProjectType
{
+ Unknown = 0,
+ CMake
}
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Data/InputData.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildSolution.cs
similarity index 83%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/Data/InputData.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildSolution.cs
index 0f1c524b..6a79f9e4 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Data/InputData.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildSolution.cs
@@ -7,7 +7,7 @@ namespace C2CS.Feature.BuildLibraryC.Data;
// NOTE: Properties are required for System.Text.Json serialization
// NOTE: This class is considered un-sanitized input; all strings and other types could be null.
-public class InputData
+public class BuildSolution
{
- public ImmutableArray? BuildTargets { get; set; }
+ public ImmutableArray Projects { get; set; }
}
diff --git a/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildTarget.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildTarget.cs
new file mode 100644
index 00000000..cea1d744
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildTarget.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.Collections.Immutable;
+
+namespace C2CS.Feature.BuildLibraryC.Data;
+
+// NOTE: Properties are required for System.Text.Json serialization
+// NOTE: This class is considered un-sanitized input; all strings and other types could be null.
+public class BuildTarget
+{
+ public NativeOperatingSystem OperatingSystem { get; set; } = NativeOperatingSystem.Unknown;
+
+ public ImmutableArray TargetArchitectures { get; set; } = ImmutableArray.Empty;
+
+ public bool IsEnabledCombineArchitectures { get; set; }
+
+ public string OutputDirectoryPath { get; set; } = string.Empty;
+}
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Domain/BuildTargetResult.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildTargetResult.cs
similarity index 92%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/Domain/BuildTargetResult.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildTargetResult.cs
index 4403518d..b741e876 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Domain/BuildTargetResult.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/BuildTargetResult.cs
@@ -1,7 +1,7 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-namespace C2CS.Feature.BuildLibraryC.Domain;
+namespace C2CS.Feature.BuildLibraryC.Data;
public class BuildTargetResult
{
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Data/Serialization/InputDataSerializerContext.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/Serialization/JsonSerializerContext.cs
similarity index 79%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/Data/Serialization/InputDataSerializerContext.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/Serialization/JsonSerializerContext.cs
index a3f676c2..9cefddef 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Data/Serialization/InputDataSerializerContext.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Data/Serialization/JsonSerializerContext.cs
@@ -10,7 +10,7 @@ namespace C2CS.Feature.BuildLibraryC.Data.Serialization;
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
GenerationMode = JsonSourceGenerationMode.Metadata)]
-[JsonSerializable(typeof(InputData))]
-internal partial class InputDataSerializerContext : JsonSerializerContext
+[JsonSerializable(typeof(BuildProject))]
+internal partial class JsonSerializerContext : System.Text.Json.Serialization.JsonSerializerContext
{
}
diff --git a/src/cs/production/features/C2CS.Feature.BuildLibraryC/Domain/CMake.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Domain/CMake.cs
new file mode 100644
index 00000000..e74a55e6
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Domain/CMake.cs
@@ -0,0 +1,148 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+// namespace C2CS.Feature.BuildLibraryC.Domain.Logic;
+//
+// public static class CMake
+// {
+// public static bool GenerateBuildFiles(string cMakeDirectoryPath, string libraryOutputDirectoryPath)
+// {
+// if (!Directory.Exists(cMakeDirectoryPath))
+// {
+// throw new DirectoryNotFoundException(cMakeDirectoryPath);
+// }
+//
+// var outPath = libraryOutputDirectoryPath.Replace("\\", "/", StringComparison.InvariantCulture);
+// var shellCommand =
+// $"cmake -S . -B cmake-build-release -DCMAKE_BUILD_TYPE=Release -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY={outPath} -DCMAKE_LIBRARY_OUTPUT_DIRECTORY={outPath} -DCMAKE_RUNTIME_OUTPUT_DIRECTORY={outPath} -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE={outPath}";
+//
+// var isSuccess = shellCommand.Shell(cMakeDirectoryPath, windowsUsePowerShell: false);
+// if (!isSuccess)
+// {
+// return false;
+// }
+//
+// isSuccess = "cmake --build cmake-build-release --config Release"
+// .Shell(cMakeDirectoryPath, windowsUsePowerShell: false);
+// if (!isSuccess)
+// {
+// return false;
+// }
+//
+// var outputDirectoryPath = Path.Combine(cMakeDirectoryPath, "lib");
+// if (!Directory.Exists(outputDirectoryPath))
+// {
+// return false;
+// }
+//
+// var runtimePlatform = Platform.HostOperatingSystem;
+// var libraryFileNameExtension = Platform.LibraryFileNameExtension(runtimePlatform);
+// var outputFilePaths = Directory.EnumerateFiles(
+// outputDirectoryPath, $"*{libraryFileNameExtension}", SearchOption.AllDirectories);
+// foreach (var outputFilePath in outputFilePaths)
+// {
+// var targetFilePath = outputFilePath.Replace(
+// outputDirectoryPath, libraryOutputDirectoryPath, StringComparison.InvariantCulture);
+// var targetFileName = Path.GetFileName(targetFilePath);
+//
+// if (runtimePlatform == RuntimeOperatingSystem.Windows)
+// {
+// if (targetFileName.StartsWith("lib", StringComparison.InvariantCulture))
+// {
+// targetFileName = targetFileName[3..];
+// }
+// }
+//
+// var targetFileDirectoryPath = Path.GetDirectoryName(targetFilePath)!;
+// targetFilePath = Path.Combine(targetFileDirectoryPath, targetFileName);
+// if (!Directory.Exists(targetFileDirectoryPath))
+// {
+// Directory.CreateDirectory(targetFileDirectoryPath);
+// }
+//
+// if (File.Exists(targetFilePath))
+// {
+// File.Delete(targetFilePath);
+// }
+//
+// File.Copy(outputFilePath, targetFilePath);
+// }
+//
+// Directory.Delete(outputDirectoryPath, true);
+// Directory.Delete($"{cMakeDirectoryPath}/cmake-build-release", true);
+//
+// return true;
+// }
+//
+// public static bool Build(string rootDirectory, string cMakeDirectoryPath, string libraryOutputDirectoryPath)
+// {
+// if (!Directory.Exists(rootDirectory))
+// {
+// throw new DirectoryNotFoundException(cMakeDirectoryPath);
+// }
+//
+// if (!Directory.Exists(cMakeDirectoryPath))
+// {
+// throw new DirectoryNotFoundException(cMakeDirectoryPath);
+// }
+//
+// var libraryOutputDirectoryPathNormalized = libraryOutputDirectoryPath.Replace("\\", "/", StringComparison.InvariantCulture);
+// var isSuccess = $"cmake -S . -B cmake-build-release -DCMAKE_BUILD_TYPE=Release -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY={libraryOutputDirectoryPathNormalized} -DCMAKE_LIBRARY_OUTPUT_DIRECTORY={libraryOutputDirectoryPathNormalized} -DCMAKE_RUNTIME_OUTPUT_DIRECTORY={libraryOutputDirectoryPathNormalized} -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE={libraryOutputDirectoryPathNormalized}"
+// .Shell(cMakeDirectoryPath, windowsUsePowerShell: false);
+// if (!isSuccess)
+// {
+// return false;
+// }
+//
+// isSuccess = "cmake --build cmake-build-release --config Release"
+// .Shell(cMakeDirectoryPath, windowsUsePowerShell: false);
+// if (!isSuccess)
+// {
+// return false;
+// }
+//
+// var outputDirectoryPath = Path.Combine(cMakeDirectoryPath, "lib");
+// if (!Directory.Exists(outputDirectoryPath))
+// {
+// return false;
+// }
+//
+// var runtimePlatform = Platform.HostOperatingSystem;
+// var libraryFileNameExtension = Platform.LibraryFileNameExtension(runtimePlatform);
+// var outputFilePaths = Directory.EnumerateFiles(
+// outputDirectoryPath, $"*{libraryFileNameExtension}", SearchOption.AllDirectories);
+// foreach (var outputFilePath in outputFilePaths)
+// {
+// var targetFilePath = outputFilePath.Replace(
+// outputDirectoryPath, libraryOutputDirectoryPath, StringComparison.InvariantCulture);
+// var targetFileName = Path.GetFileName(targetFilePath);
+//
+// if (runtimePlatform == RuntimeOperatingSystem.Windows)
+// {
+// if (targetFileName.StartsWith("lib", StringComparison.InvariantCulture))
+// {
+// targetFileName = targetFileName[3..];
+// }
+// }
+//
+// var targetFileDirectoryPath = Path.GetDirectoryName(targetFilePath)!;
+// targetFilePath = Path.Combine(targetFileDirectoryPath, targetFileName);
+// if (!Directory.Exists(targetFileDirectoryPath))
+// {
+// Directory.CreateDirectory(targetFileDirectoryPath);
+// }
+//
+// if (File.Exists(targetFilePath))
+// {
+// File.Delete(targetFilePath);
+// }
+//
+// File.Copy(outputFilePath, targetFilePath);
+// }
+//
+// Directory.Delete(outputDirectoryPath, true);
+// Directory.Delete($"{cMakeDirectoryPath}/cmake-build-release", true);
+//
+// return true;
+// }
+// }
diff --git a/src/cs/production/C2CS.Feature.BuildLibraryC/Handler.cs b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Startup.cs
similarity index 51%
rename from src/cs/production/C2CS.Feature.BuildLibraryC/Handler.cs
rename to src/cs/production/features/C2CS.Feature.BuildLibraryC/Startup.cs
index be8686fc..f2e7f2a4 100644
--- a/src/cs/production/C2CS.Feature.BuildLibraryC/Handler.cs
+++ b/src/cs/production/features/C2CS.Feature.BuildLibraryC/Startup.cs
@@ -1,15 +1,15 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using Microsoft.Extensions.DependencyInjection;
+
namespace C2CS.Feature.BuildLibraryC;
-public class Handler : UseCaseHandler
+public static class Startup
{
- protected override void Execute(Input input, Output output)
+ public static void ConfigureServices(IServiceCollection services)
{
- foreach (var buildTarget in input.BuildTargets)
- {
- Console.WriteLine(buildTarget);
- }
+ services.AddSingleton();
+ services.AddSingleton();
}
}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/C2CS.Feature.ReadCodeC.csproj b/src/cs/production/features/C2CS.Feature.ReadCodeC/C2CS.Feature.ReadCodeC.csproj
new file mode 100644
index 00000000..b87bbaba
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/C2CS.Feature.ReadCodeC.csproj
@@ -0,0 +1,23 @@
+
+
+
+
+ net6.0
+ enable
+ enable
+ $(NoWarn);CA1724
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/C2CS.Feature.ReadCodeC.csproj.DotSettings b/src/cs/production/features/C2CS.Feature.ReadCodeC/C2CS.Feature.ReadCodeC.csproj.DotSettings
new file mode 100644
index 00000000..39563875
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/C2CS.Feature.ReadCodeC.csproj.DotSettings
@@ -0,0 +1,11 @@
+
+ False
+ False
+ False
+ False
+ False
+ True
+ False
+ False
+ True
+ True
\ No newline at end of file
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CAbstractSyntaxTree.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CAbstractSyntaxTree.cs
similarity index 85%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CAbstractSyntaxTree.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CAbstractSyntaxTree.cs
index d48f3e52..f47e8708 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CAbstractSyntaxTree.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CAbstractSyntaxTree.cs
@@ -3,19 +3,17 @@
using System.Collections.Immutable;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
public record CAbstractSyntaxTree
{
[JsonPropertyName("fileName")]
public string FileName { get; set; } = string.Empty;
- [JsonPropertyName("bitness")]
- public int Bitness { get; set; }
+ [JsonPropertyName("platform")]
+ public TargetPlatform Platform { get; set; } = TargetPlatform.Unknown;
[JsonPropertyName("functions")]
public ImmutableArray Functions { get; set; } = ImmutableArray.Empty;
@@ -29,9 +27,6 @@ public record CAbstractSyntaxTree
[JsonPropertyName("enums")]
public ImmutableArray Enums { get; set; } = ImmutableArray.Empty;
- [JsonPropertyName("pseudoEnums")]
- public ImmutableArray PseudoEnums { get; set; } = ImmutableArray.Empty;
-
[JsonPropertyName("opaqueTypes")]
public ImmutableArray OpaqueTypes { get; set; } = ImmutableArray.Empty;
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CEnum.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CEnum.cs
similarity index 79%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CEnum.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CEnum.cs
index c8c31bf4..64b5ba50 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CEnum.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CEnum.cs
@@ -2,14 +2,13 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CEnum : CNode
+public record CEnum : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -23,8 +22,9 @@ public record CEnum : CNode
[JsonPropertyName("values")]
public ImmutableArray Values { get; set; } = ImmutableArray.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"Enum '{Type}': {IntegerType} @ {Location.ToString()}";
+ return $"Enum '{Type}': {IntegerType} @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CEnumValue.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CEnumValue.cs
similarity index 76%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CEnumValue.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CEnumValue.cs
index b681366a..0aa528a1 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CEnumValue.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CEnumValue.cs
@@ -1,13 +1,12 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
public record CEnumValue : CNode
{
[JsonPropertyName("name")]
@@ -16,8 +15,9 @@ public record CEnumValue : CNode
[JsonPropertyName("value")]
public long Value { get; set; }
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"EnumValue '{Name}' = {Value} @ {Location.ToString()}";
+ return $"EnumValue '{Name}' = {Value}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunction.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunction.cs
similarity index 81%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunction.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunction.cs
index 913093b6..ea6d27ef 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunction.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunction.cs
@@ -2,14 +2,13 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CFunction : CNode
+public record CFunction : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -23,8 +22,9 @@ public record CFunction : CNode
[JsonPropertyName("parameters")]
public ImmutableArray Parameters { get; set; } = ImmutableArray.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"FunctionExtern '{Name}' @ {Location.ToString()}";
+ return $"FunctionExtern '{Name}' @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionCallingConvention.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionCallingConvention.cs
similarity index 83%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionCallingConvention.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionCallingConvention.cs
index af72063a..2bb3bb71 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionCallingConvention.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionCallingConvention.cs
@@ -1,7 +1,7 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
public enum CFunctionCallingConvention
{
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionParameter.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionParameter.cs
similarity index 78%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionParameter.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionParameter.cs
index cd264878..49ae1d02 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionParameter.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionParameter.cs
@@ -1,14 +1,13 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CFunctionParameter : CNode
+public record CFunctionParameter : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -16,8 +15,9 @@ public record CFunctionParameter : CNode
[JsonPropertyName("type")]
public string Type { get; set; } = string.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"FunctionExternParameter '{Name}': {Type} @ {Location.ToString()}";
+ return $"FunctionExternParameter '{Name}': {Type} @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionPointer.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionPointer.cs
similarity index 80%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionPointer.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionPointer.cs
index 41d43e96..435427e5 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionPointer.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionPointer.cs
@@ -2,14 +2,13 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CFunctionPointer : CNode
+public record CFunctionPointer : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -24,8 +23,9 @@ public record CFunctionPointer : CNode
public ImmutableArray Parameters { get; set; } =
ImmutableArray.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"FunctionPointer {Type} @ {Location.ToString()}";
+ return $"FunctionPointer {Type} @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionPointerParameter.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionPointerParameter.cs
similarity index 77%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionPointerParameter.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionPointerParameter.cs
index 0c6cf945..7b17037f 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CFunctionPointerParameter.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CFunctionPointerParameter.cs
@@ -1,14 +1,13 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CFunctionPointerParameter : CNode
+public record CFunctionPointerParameter : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -16,8 +15,9 @@ public record CFunctionPointerParameter : CNode
[JsonPropertyName("type")]
public string Type { get; set; } = null!;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"FunctionPointerParameter '{Name}': {Type} @ {Location.ToString()}";
+ return $"FunctionPointerParameter '{Name}': {Type} @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CKind.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CKind.cs
similarity index 88%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CKind.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CKind.cs
index 84acd65f..8ad7e05d 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CKind.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CKind.cs
@@ -1,7 +1,7 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
public enum CKind
{
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CLocation.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CLocation.cs
new file mode 100644
index 00000000..2df66ba4
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CLocation.cs
@@ -0,0 +1,95 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.Text.Json.Serialization;
+
+namespace C2CS.Feature.ReadCodeC.Data;
+
+// NOTE: Properties are required for System.Text.Json serialization
+
+public record struct CLocation : IComparable
+{
+#pragma warning disable CA2211
+ public static CLocation System = new()
+ {
+ IsSystem = true
+ };
+#pragma warning restore CA2211
+
+ [JsonPropertyName("fileName")]
+ public string FileName { get; set; }
+
+ [JsonPropertyName("filePath")]
+ public string FilePath { get; set; }
+
+ [JsonPropertyName("line")]
+ public int LineNumber { get; set; }
+
+ [JsonPropertyName("column")]
+ public int LineColumn { get; set; }
+
+ [JsonIgnore]
+ public bool IsSystem { get; set; }
+
+ public override string ToString()
+ {
+#pragma warning disable CA1308
+ if (IsSystem)
+ {
+ return nameof(System);
+ }
+#pragma warning restore CA1308
+
+ if (LineNumber == 0 && LineColumn == 0)
+ {
+ return $"{FileName}";
+ }
+
+ return string.IsNullOrEmpty(FilePath) || FilePath == FileName
+ ? $"{FileName}:{LineNumber}:{LineColumn}"
+ : $"{FileName}:{LineNumber}:{LineColumn} ({FilePath})";
+ }
+
+ public int CompareTo(CLocation other)
+ {
+ var result = string.Compare(FileName, other.FileName, StringComparison.Ordinal);
+ if (result != 0)
+ {
+ return result;
+ }
+
+ result = LineNumber.CompareTo(other.LineNumber);
+ if (result != 0)
+ {
+ return result;
+ }
+
+ result = LineColumn.CompareTo(other.LineColumn);
+ if (result != 0)
+ {
+ return result;
+ }
+
+ return result;
+ }
+
+ public static bool operator <(CLocation first, CLocation second)
+ {
+ return first.CompareTo(second) < 0;
+ }
+
+ public static bool operator >(CLocation first, CLocation second)
+ {
+ return first.CompareTo(second) > 0;
+ }
+
+ public static bool operator >=(CLocation first, CLocation second)
+ {
+ return first.CompareTo(second) >= 0;
+ }
+
+ public static bool operator <=(CLocation first, CLocation second)
+ {
+ return first.CompareTo(second) <= 0;
+ }
+}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CMacroDefinition.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CMacroDefinition.cs
similarity index 72%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CMacroDefinition.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CMacroDefinition.cs
index 65458ba1..64d2f835 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CMacroDefinition.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CMacroDefinition.cs
@@ -2,11 +2,12 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
-public record CMacroDefinition : CNode
+public record CMacroDefinition : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -14,8 +15,9 @@ public record CMacroDefinition : CNode
[JsonPropertyName("tokens")]
public ImmutableArray Tokens { get; set; } = ImmutableArray.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"Macro '{Name}' @ {Location.ToString()}";
+ return $"Macro '{Name}' @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CNode.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CNode.cs
similarity index 85%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CNode.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CNode.cs
index d9e06735..0abaec15 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CNode.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CNode.cs
@@ -2,17 +2,12 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CNode : IComparable
+public abstract record CNode : IComparable
{
- [JsonPropertyName("location")]
- public ClangLocation Location { get; set; }
-
[JsonIgnore]
public CKind Kind => GetKind();
@@ -28,10 +23,15 @@ public int CompareTo(CNode? other)
return 1;
}
- var result = Location.CompareTo(other.Location);
+ var result = CompareToInternal(other);
return result;
}
+ protected virtual int CompareToInternal(CNode? other)
+ {
+ return 0;
+ }
+
private CKind GetKind()
{
return this switch
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CNodeWithLocation.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CNodeWithLocation.cs
new file mode 100644
index 00000000..1495dd8d
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CNodeWithLocation.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.Text.Json.Serialization;
+using C2CS.Feature.ReadCodeC.Data.Serialization;
+
+namespace C2CS.Feature.ReadCodeC.Data;
+
+public abstract record CNodeWithLocation : CNode
+{
+ [JsonPropertyName("location")]
+ [JsonConverter(typeof(CLocationJsonConverter))]
+ public CLocation Location { get; set; }
+
+ protected override int CompareToInternal(CNode? other)
+ {
+ if (other is not CNodeWithLocation other2)
+ {
+ return base.CompareToInternal(other);
+ }
+
+ return Location.CompareTo(other2.Location);
+ }
+}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/COpaqueType.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/COpaqueType.cs
similarity index 65%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/COpaqueType.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/COpaqueType.cs
index 0a703c7a..b5d8dd1a 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/COpaqueType.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/COpaqueType.cs
@@ -1,17 +1,19 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
-public record COpaqueType : CNode
+public record COpaqueType : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"OpaqueType '{Name}' @ {Location.ToString()}";
+ return $"OpaqueType '{Name}' @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CRecord.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CRecord.cs
similarity index 81%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CRecord.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CRecord.cs
index d72dbbde..dd64ee52 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CRecord.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CRecord.cs
@@ -2,14 +2,13 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CRecord : CNode
+public record CRecord : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -23,9 +22,10 @@ public record CRecord : CNode
[JsonPropertyName("nestedRecords")]
public ImmutableArray NestedRecords { get; set; } = ImmutableArray.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
var kind = IsUnion ? "Union" : "Struct";
- return $"{kind} {Name} @ {Location.ToString()}";
+ return $"{kind} {Name} @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CRecordField.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CRecordField.cs
similarity index 76%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CRecordField.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CRecordField.cs
index 6fb40ec1..1c8499db 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CRecordField.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CRecordField.cs
@@ -1,14 +1,13 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CRecordField : CNode
+public record CRecordField : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -22,8 +21,9 @@ public record CRecordField : CNode
[JsonPropertyName("padding")]
public int Padding { get; set; }
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"RecordField '{Name}': {Type} @ {Location.ToString()}";
+ return $"RecordField '{Name}': {Type} @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CType.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CType.cs
similarity index 75%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CType.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CType.cs
index 7fdea27d..9a62b074 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CType.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CType.cs
@@ -1,13 +1,13 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
+using C2CS.Feature.ReadCodeC.Data.Serialization;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
public class CType
{
[JsonPropertyName("name")]
@@ -28,15 +28,11 @@ public class CType
[JsonPropertyName("arraySize")]
public int? ArraySize { get; set; }
- [JsonPropertyName("isSystem")]
- public bool IsSystem { get; set; }
-
- [JsonPropertyName("isAnonymous")]
- public bool IsAnonymous { get; set; }
-
[JsonPropertyName("location")]
- public ClangLocation? Location { get; set; }
+ [JsonConverter(typeof(CLocationJsonConverter))]
+ public CLocation Location { get; set; }
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
return Name;
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CTypedef.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CTypedef.cs
similarity index 72%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CTypedef.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CTypedef.cs
index b4c459d2..7dd492da 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CTypedef.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CTypedef.cs
@@ -1,14 +1,13 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using JetBrains.Annotations;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
// NOTE: Properties are required for System.Text.Json serialization
-[PublicAPI]
-public record CTypedef : CNode
+public record CTypedef : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -16,8 +15,9 @@ public record CTypedef : CNode
[JsonPropertyName("underlyingType")]
public string UnderlyingType { get; set; } = string.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"Record '{Name}': {UnderlyingType} @ {Location.ToString()}";
+ return $"Record '{Name}': {UnderlyingType} @ {Location}";
}
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CVariable.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CVariable.cs
similarity index 69%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CVariable.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CVariable.cs
index 68507c88..9c350e3a 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/CVariable.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/CVariable.cs
@@ -1,11 +1,12 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+namespace C2CS.Feature.ReadCodeC.Data;
-public record CVariable : CNode
+public record CVariable : CNodeWithLocation
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
@@ -13,8 +14,9 @@ public record CVariable : CNode
[JsonPropertyName("type")]
public string Type { get; set; } = string.Empty;
+ [ExcludeFromCodeCoverage]
public override string ToString()
{
- return $"Variable '{Name}': {Type} @ {Location.ToString()}";
+ return $"Variable '{Name}': {Type} @ {Location}";
}
}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/ReadCodeCConfiguration.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/ReadCodeCConfiguration.cs
new file mode 100644
index 00000000..22842736
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/ReadCodeCConfiguration.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.Text.Json.Serialization;
+using C2CS.Foundation.UseCases;
+using JetBrains.Annotations;
+
+namespace C2CS.Feature.ReadCodeC.Data;
+
+// NOTE: Properties are required for System.Text.Json serialization
+// NOTE: This class is considered un-sanitized input; all strings and other types could be null.
+// NOTE: This class must have a unique name across namespaces for usage in System.Text.Json source generators.
+[PublicAPI]
+public sealed class ReadCodeCConfiguration : UseCaseConfiguration
+{
+ [JsonPropertyName("input_file")]
+ [Json.Schema.Generation.Description("Path of the input `.h` header file containing C code.")]
+ public string? InputFilePath { get; set; }
+
+ [JsonPropertyName("platforms")]
+ [Json.Schema.Generation.Description("The target platform configurations for extracting the abstract syntax trees. Each target platform is a Clang target triple. See the C2CS docs for more details about what target platforms are available.")]
+#pragma warning disable CA2227
+ public Dictionary? ConfigurationAbstractSyntaxTrees { get; set; }
+#pragma warning restore CA2227
+}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/ReadCodeCConfigurationAbstractSyntaxTree.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/ReadCodeCConfigurationAbstractSyntaxTree.cs
new file mode 100644
index 00000000..0eb10105
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/ReadCodeCConfigurationAbstractSyntaxTree.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.Collections.Immutable;
+using System.Text.Json.Serialization;
+using JetBrains.Annotations;
+
+namespace C2CS.Feature.ReadCodeC.Data;
+
+[PublicAPI]
+public sealed class ReadCodeCConfigurationAbstractSyntaxTree
+{
+ [JsonIgnore]
+ public string? OutputFileDirectory { get; set; }
+
+ [JsonPropertyName("find_system_headers")]
+ [Json.Schema.Generation.Description("Determines whether system C/C++ headers are attempted to be found and passed to Clang. Default is `true`.")]
+ public bool? IsEnabledFindSystemHeaders { get; set; } = true;
+
+ [JsonPropertyName("include")]
+ [Json.Schema.Generation.Description("Search directory paths to use for `#include` usages when parsing C code.")]
+ public ImmutableArray? IncludeDirectories { get; set; }
+
+ [JsonPropertyName("defines")]
+ [Json.Schema.Generation.Description("Object-like macros to use when parsing C code.")]
+ public ImmutableArray? Defines { get; set; }
+
+ [JsonPropertyName("exclude")]
+ [Json.Schema.Generation.Description("C header file names to exclude. File names are relative to the `IncludeDirectories` property.")]
+ public ImmutableArray? ExcludedHeaderFiles { get; set; }
+
+ [JsonPropertyName("function_names")]
+ [Json.Schema.Generation.Description("The C function names to explicitly include when parsing C code. Default is `null`. If `null<`, no white list applies. Note that C function names which are excluded also exclude any transitive types.")]
+ public ImmutableArray? FunctionNamesWhiteList { get; set; }
+
+ [JsonPropertyName("opaque_names")]
+ [Json.Schema.Generation.Description("Type names that may be found when parsing C code that will be interpreted as opaque types. Opaque types are often used with a pointer to hide the information about the bit layout behind the pointer.")]
+ public ImmutableArray? OpaqueTypeNames { get; set; }
+
+ [Json.Schema.Generation.Description("Additional Clang arguments to use when parsing C code.")]
+ [JsonPropertyName("clang_arguments")]
+ public ImmutableArray? ClangArguments { get; set; }
+}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CJsonSerializer.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CJsonSerializer.cs
new file mode 100644
index 00000000..cef45be6
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CJsonSerializer.cs
@@ -0,0 +1,94 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.IO.Abstractions;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Microsoft.Extensions.Logging;
+
+namespace C2CS.Feature.ReadCodeC.Data.Serialization;
+
+public class CJsonSerializer
+{
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
+ private readonly CJsonSerializerContext _context;
+
+ public CJsonSerializer(ILogger logger, IFileSystem fileSystem)
+ {
+ _logger = logger;
+ _fileSystem = fileSystem;
+
+ var serializerOptions = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ Converters =
+ {
+ new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
+ },
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
+ };
+ _context = new CJsonSerializerContext(serializerOptions);
+ }
+
+ public CAbstractSyntaxTree Read(string filePath)
+ {
+ CAbstractSyntaxTree result;
+
+ var fullFilePath = _fileSystem.Path.GetFullPath(filePath);
+
+ try
+ {
+ var fileContents = _fileSystem.File.ReadAllText(fullFilePath);
+ result = JsonSerializer.Deserialize(fileContents, _context.CAbstractSyntaxTree)!;
+ _logger.ReadAbstractSyntaxTreeCSuccess(fullFilePath);
+ }
+ catch (Exception e)
+ {
+ _logger.ReadAbstractSyntaxTreeCFailure(fullFilePath, e);
+ throw;
+ }
+
+ return result;
+ }
+
+ public void Write(CAbstractSyntaxTree abstractSyntaxTree, string filePath)
+ {
+ var fullFilePath = _fileSystem.Path.GetFullPath(filePath);
+
+ var outputDirectory = _fileSystem.Path.GetDirectoryName(fullFilePath)!;
+ if (string.IsNullOrEmpty(outputDirectory))
+ {
+ outputDirectory = AppContext.BaseDirectory;
+ fullFilePath = Path.Combine(Environment.CurrentDirectory, fullFilePath);
+ }
+
+ try
+ {
+ if (!_fileSystem.Directory.Exists(outputDirectory))
+ {
+ _fileSystem.Directory.CreateDirectory(outputDirectory);
+ }
+
+ if (_fileSystem.File.Exists(fullFilePath))
+ {
+ _fileSystem.File.Delete(fullFilePath);
+ }
+
+ var fileContents = JsonSerializer.Serialize(abstractSyntaxTree, _context.Options);
+
+ using var fileStream = _fileSystem.File.OpenWrite(fullFilePath);
+ using var textWriter = new StreamWriter(fileStream);
+ textWriter.Write(fileContents);
+ textWriter.Close();
+ fileStream.Close();
+
+ _logger.WriteAbstractSyntaxTreeCSuccess(fullFilePath);
+ }
+ catch (Exception e)
+ {
+ _logger.WriteAbstractSyntaxTreeCFailure(fullFilePath, e);
+ throw;
+ }
+ }
+}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/Serialization/CJsonSerializerContext.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CJsonSerializerContext.cs
similarity index 89%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/Serialization/CJsonSerializerContext.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CJsonSerializerContext.cs
index b8186fbe..82033211 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Data/Serialization/CJsonSerializerContext.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CJsonSerializerContext.cs
@@ -3,7 +3,7 @@
using System.Text.Json.Serialization;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Data.Serialization;
+namespace C2CS.Feature.ReadCodeC.Data.Serialization;
[JsonSourceGenerationOptions(
WriteIndented = true,
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CLocationJsonConverter.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CLocationJsonConverter.cs
new file mode 100644
index 00000000..9c427ef1
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/CLocationJsonConverter.cs
@@ -0,0 +1,34 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace C2CS.Feature.ReadCodeC.Data.Serialization;
+
+#pragma warning disable CA1308
+
+public class CLocationJsonConverter : JsonConverter
+{
+ public override CLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.StartObject)
+ {
+ return JsonSerializer.Deserialize(ref reader, options);
+ }
+
+ return CLocation.System;
+ }
+
+ public override void Write(Utf8JsonWriter writer, CLocation value, JsonSerializerOptions options)
+ {
+ if (value.IsSystem)
+ {
+ writer.WriteNullValue();
+ }
+ else
+ {
+ JsonSerializer.Serialize(writer, value, options);
+ }
+ }
+}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/Logging.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/Logging.cs
new file mode 100644
index 00000000..21c61ffa
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Data/Serialization/Logging.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using C2CS.Foundation;
+using C2CS.Foundation.Logging;
+using Microsoft.Extensions.Logging;
+
+namespace C2CS.Feature.ReadCodeC.Data.Serialization;
+
+internal static class Logging
+{
+ private static readonly Action ActionReadAbstractSyntaxTreeSuccess =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Serialize abstract syntax tree C: success."),
+ "- Read abstract syntax tree C: Success. Path: {FilePath}");
+
+ private static readonly Action ActionReadAbstractSyntaxTreeFailure =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Serialize abstract syntax tree C: failure."),
+ "- Read abstract syntax tree C. Failed. Path: {FilePath}.");
+
+ private static readonly Action ActionWriteAbstractSyntaxTreeSuccess =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Write abstract syntax tree C: success."),
+ "- Write abstract syntax tree C: Success. Path: {FilePath}");
+
+ private static readonly Action ActionWriteAbstractSyntaxTreeFailure =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Write abstract syntax tree C: failure."),
+ "- Write abstract syntax tree C. Failed. Path: {FilePath}.");
+
+ public static void ReadAbstractSyntaxTreeCSuccess(this ILogger logger, string filePath)
+ {
+ ActionReadAbstractSyntaxTreeSuccess(logger, filePath, null!);
+ }
+
+ public static void ReadAbstractSyntaxTreeCFailure(this ILogger logger, string filePath, Exception exception)
+ {
+ ActionReadAbstractSyntaxTreeFailure(logger, filePath, exception);
+ }
+
+ public static void WriteAbstractSyntaxTreeCSuccess(this ILogger logger, string filePath)
+ {
+ ActionWriteAbstractSyntaxTreeSuccess(logger, filePath, null!);
+ }
+
+ public static void WriteAbstractSyntaxTreeCFailure(this ILogger logger, string filePath, Exception exception)
+ {
+ ActionWriteAbstractSyntaxTreeFailure(logger, filePath, exception);
+ }
+}
diff --git a/src/cs/production/clang-cs/ClangException.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ClangException.cs
similarity index 83%
rename from src/cs/production/clang-cs/ClangException.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ClangException.cs
index 5877f1a2..ee3cff5e 100644
--- a/src/cs/production/clang-cs/ClangException.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ClangException.cs
@@ -1,9 +1,9 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-using System;
+namespace C2CS.Feature.ReadCodeC.Domain;
-public class ClangException : Exception
+public sealed class ClangException : Exception
{
public ClangException()
{
diff --git a/src/cs/production/clang-cs/ClangExtensions.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ClangExtensions.cs
similarity index 87%
rename from src/cs/production/clang-cs/ClangExtensions.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ClangExtensions.cs
index 93a29a01..c980caf2 100644
--- a/src/cs/production/clang-cs/ClangExtensions.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ClangExtensions.cs
@@ -1,14 +1,14 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
-using System.IO;
using System.Runtime.InteropServices;
-using System.Threading;
+using C2CS.Feature.ReadCodeC.Data;
using static bottlenoselabs.clang;
+namespace C2CS.Feature.ReadCodeC.Domain;
+
public static unsafe class ClangExtensions
{
public delegate bool VisitPredicate(CXCursor child, CXCursor parent);
@@ -262,56 +262,18 @@ private static string NameInternal(this CXType clangType)
return result;
}
- public static ClangLocation FileLocation(this CXType type, CXCursor cursor)
+ public static CLocation FileLocation(this CXType type, CXCursor cursor)
{
- // The cursor type could be a pointer, which if so, we need to drill down to the pointee type
- // if we don't, then the location will be the declaration of where the pointer is used which is not
- // probably the expected outcome
- // however... function pointers are a special case to which they don't have a declaration unless they are
- // from a typedef
- CXCursor declaration;
-
- if (type.kind == CXTypeKind.CXType_Attributed)
- {
- type = clang_Type_getModifiedType(type);
- }
-
- if (type.kind == CXTypeKind.CXType_Pointer)
- {
- type = clang_getPointeeType(type);
- }
-
- if (type.kind == CXTypeKind.CXType_FunctionProto ||
- type.kind == CXTypeKind.CXType_FunctionNoProto)
- {
- declaration = cursor;
- }
- else
- {
- while (type.kind == CXTypeKind.CXType_Pointer)
- {
- type = clang_getPointeeType(type);
- }
-
- if (type.IsPrimitive())
- {
- declaration = cursor;
- }
- else
- {
- declaration = clang_getTypeDeclaration(type);
- }
- }
-
+ var declaration = type.IsPrimitive() ? cursor : clang_getTypeDeclaration(type);
return FileLocation(declaration);
}
- public static ClangLocation FileLocation(this CXCursor cursor)
+ public static CLocation FileLocation(this CXCursor cursor)
{
if (cursor.kind == CXCursorKind.CXCursor_TranslationUnit)
{
var filePath = cursor.Name();
- return new ClangLocation
+ return new CLocation
{
FileName = Path.GetFileName(filePath),
FilePath = filePath
@@ -326,10 +288,22 @@ public static ClangLocation FileLocation(this CXCursor cursor)
clang_getFileLocation(location, &file, &lineNumber, &columnNumber, &offset);
+ var isInSystemHeader = clang_Location_isInSystemHeader(location) > 0U;
+ if (isInSystemHeader)
+ {
+ return CLocation.System;
+ }
+
+ var isPrimitive = clang_getCursorType(cursor).IsPrimitive();
+ if (isPrimitive)
+ {
+ return CLocation.System;
+ }
+
var handle = (IntPtr)file.Data;
if (handle == IntPtr.Zero)
{
- return new ClangLocation
+ return new CLocation
{
FileName = string.Empty
};
@@ -338,13 +312,12 @@ public static ClangLocation FileLocation(this CXCursor cursor)
var fileName = clang_getFileName(file);
string fileNamePath = clang_getCString(fileName);
- return new ClangLocation
+ return new CLocation
{
FileName = Path.GetFileName(fileNamePath),
FilePath = string.IsNullOrEmpty(fileNamePath) ? string.Empty : Path.GetFullPath(fileNamePath),
LineNumber = (int)lineNumber,
- LineColumn = (int)columnNumber,
- IsBuiltin = clang_getCursorType(cursor).IsPrimitive()
+ LineColumn = (int)columnNumber
};
}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Logic/CTranslationUnitExplorer.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorer.cs
similarity index 65%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Logic/CTranslationUnitExplorer.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorer.cs
index 3880604d..3f938a97 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Logic/CTranslationUnitExplorer.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorer.cs
@@ -3,279 +3,152 @@
using System.Collections.Immutable;
using System.Diagnostics;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Diagnostics;
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Domain;
+using C2CS.Feature.ReadCodeC.Data;
+using C2CS.Feature.ReadCodeC.Domain.ExploreCode.Diagnostics;
+using C2CS.Foundation.UseCases.Exceptions;
+using Microsoft.Extensions.Logging;
using static bottlenoselabs.clang;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Logic;
+namespace C2CS.Feature.ReadCodeC.Domain.ExploreCode;
-public class CTranslationUnitExplorer
+public sealed class ClangTranslationUnitExplorer
{
- private readonly DiagnosticsSink _diagnostics;
- private readonly List _enums = new();
- private readonly ArrayDeque _frontierGeneral = new();
- private readonly ArrayDeque _frontierMacros = new();
- private readonly List _functionPointers = new();
- private readonly List _functions = new();
- private readonly ImmutableHashSet _ignoredFiles;
-
- private readonly HashSet _ignoredMacroTokens = new()
- {
- // print conversion specifiers
- "PRId8",
- "PRId16",
- "PRId32",
- "PRId64",
- "PRIdFAST8",
- "PRIdFAST16",
- "PRIdFAST32",
- "PRIdFAST64",
- "PRIdLEAST8",
- "PRIdLEAST16",
- "PRIdLEAST32",
- "PRIdLEAST64",
- "PRIdMAX",
- "PRIdPTR",
- "PRIi8",
- "PRIi16",
- "PRIi32",
- "PRIi64",
- "PRIiFAST8",
- "PRIiFAST16",
- "PRIiFAST32",
- "PRIiFAST64",
- "PRIiLEAST8",
- "PRIiLEAST16",
- "PRIiLEAST32",
- "PRIiLEAST64",
- "PRIiMAX",
- "PRIiPTR",
- "PRIo8",
- "PRIo16",
- "PRIo32",
- "PRIo64",
- "PRIoFAST8",
- "PRIoFAST16",
- "PRIoFAST32",
- "PRIoFAST64",
- "PRIoLEAST8",
- "PRIoLEAST16",
- "PRIoLEAST32",
- "PRIoLEAST64",
- "PRIoMAX",
- "PRIoPTR",
- "PRIu8",
- "PRIu16",
- "PRIu32",
- "PRIu64",
- "PRIuFAST8",
- "PRIuFAST16",
- "PRIuFAST32",
- "PRIuFAST64",
- "PRIuLEAST8",
- "PRIuLEAST16",
- "PRIuLEAST32",
- "PRIuLEAST64",
- "PRIuMAX",
- "PRIuPTR",
- "PRIx8",
- "PRIx16",
- "PRIx32",
- "PRIx64",
- "PRIxFAST8",
- "PRIxFAST16",
- "PRIxFAST32",
- "PRIxFAST64",
- "PRIxLEAST8",
- "PRIxLEAST16",
- "PRIxLEAST32",
- "PRIxLEAST64",
- "PRIxMAX",
- "PRIxPTR",
- "PRIX8",
- "PRIX16",
- "PRIX32",
- "PRIX64",
- "PRIXFAST8",
- "PRIXFAST16",
- "PRIXFAST32",
- "PRIXFAST64",
- "PRIXLEAST8",
- "PRIXLEAST16",
- "PRIXLEAST32",
- "PRIXLEAST64",
- "PRIXMAX",
- "PRIXPTR"
- };
-
- private readonly ImmutableArray _includeDirectories;
- private readonly ImmutableHashSet _functionNamesWhitelist;
- private readonly HashSet _macroFunctionLikeNames = new();
-
- private readonly List _macroObjects = new();
-
- private readonly HashSet _names = new();
- private readonly List _opaqueDataTypes = new();
- private readonly ImmutableHashSet _opaqueTypeNames;
- private readonly List _pseudoEnums = new();
- private readonly List _records = new();
-
- private readonly HashSet _systemIgnoredTypeNames = new()
- {
- "FILE",
- "DIR",
- "size_t",
- "ssize_t",
- "int8_t",
- "uint8_t",
- "int16_t",
- "uint16_t",
- "int32_t",
- "uint32_t",
- "int64_t",
- "uint64_t",
- "uintptr_t",
- "intptr_t",
- "va_list"
- };
-
- private readonly List _typedefs = new();
- private readonly List _types = new();
- private readonly Dictionary _typesByName = new();
- private readonly Dictionary _validTypeNames = new();
- private readonly List _variables = new();
-
- public CTranslationUnitExplorer(
- DiagnosticsSink diagnostics,
- ImmutableArray includeDirectories,
- ImmutableArray ignoredFiles,
- ImmutableArray opaqueTypes,
- ImmutableArray functionNamesWhitelist)
+ private readonly ILogger _logger;
+
+ public ClangTranslationUnitExplorer(ILogger logger)
{
- _diagnostics = diagnostics;
- _ignoredFiles = ignoredFiles.ToImmutableHashSet();
- _includeDirectories = includeDirectories;
- _opaqueTypeNames = opaqueTypes.ToImmutableHashSet();
- _functionNamesWhitelist = functionNamesWhitelist.ToImmutableHashSet();
+ _logger = logger;
}
- public CAbstractSyntaxTree AbstractSyntaxTree(CXTranslationUnit translationUnit, int bitness)
+ public CAbstractSyntaxTree AbstractSyntaxTree(
+ ClangTranslationUnitExplorerContext context, CXTranslationUnit translationUnit)
{
- VisitTranslationUnit(translationUnit);
- Explore();
+ CAbstractSyntaxTree result;
- var cursor = clang_getTranslationUnitCursor(translationUnit);
- var location = Location(cursor);
-
- var functions = _functions.ToImmutableArray();
- var functionPointers = _functionPointers.ToImmutableArray();
- var records = _records.ToImmutableArray();
- var enums = _enums.ToImmutableArray();
- var opaqueTypes = _opaqueDataTypes.ToImmutableArray();
- var typedefs = _typedefs.ToImmutableArray();
- var variables = _variables.ToImmutableArray();
- var constants = _macroObjects.ToImmutableArray();
-
- var pseudoEnums = new List();
- var enumNames = _enums.Select(x => x.Name).ToImmutableHashSet();
- foreach (var pseudoEnum in _pseudoEnums)
- {
- if (!enumNames.Contains(pseudoEnum.Name))
- {
- pseudoEnums.Add(pseudoEnum);
- }
+ try
+ {
+ VisitTranslationUnit(context, translationUnit);
+ Explore(context);
+ result = Result(context, translationUnit);
+ _logger.ExploreCodeSuccess();
}
+ catch (Exception e)
+ {
+ _logger.ExploreCodeFailed(e);
+ throw;
+ }
+
+ return result;
+ }
+
+ private CAbstractSyntaxTree Result(
+ ClangTranslationUnitExplorerContext context,
+ CXTranslationUnit translationUnit)
+ {
+ var cursor = clang_getTranslationUnitCursor(translationUnit);
+ var location = Location(context, cursor);
+
+ var functions = context.Functions.ToImmutableArray();
+ var functionPointers = context.FunctionPointers.ToImmutableArray();
+ var records = context.Records.ToImmutableArray();
+ var enums = context.Enums.ToImmutableArray();
+ var opaqueTypes = context.OpaqueDataTypes.ToImmutableArray();
+ var typedefs = context.Typedefs.ToImmutableArray();
+ var variables = context.Variables.ToImmutableArray();
+ var constants = context.MacroObjects.ToImmutableArray();
- return new CAbstractSyntaxTree
+ var result = new CAbstractSyntaxTree
{
FileName = location.FileName,
- Bitness = bitness,
+ Platform = context.TargetPlatform,
Functions = functions,
FunctionPointers = functionPointers,
Records = records,
Enums = enums,
- PseudoEnums = pseudoEnums.ToImmutableArray(),
OpaqueTypes = opaqueTypes,
Typedefs = typedefs,
Variables = variables,
- Types = _types.ToImmutableArray(),
+ Types = context.Types.ToImmutableArray(),
Constants = constants
};
+
+ return result;
}
- private void VisitTranslationUnit(CXTranslationUnit translationUnit)
+ private void VisitTranslationUnit(ClangTranslationUnitExplorerContext context, CXTranslationUnit translationUnit)
{
var cursor = clang_getTranslationUnitCursor(translationUnit);
var type = clang_getCursorType(cursor);
- var location = Location(cursor);
+ var location = Location(context, cursor);
+
+ _logger.ExploreCodeTranslationUnit(location.FileName);
AddExplorerNode(
+ context,
CKind.TranslationUnit,
location,
null,
cursor,
type,
- type,
string.Empty,
string.Empty);
}
- private void Explore()
+ private void Explore(ClangTranslationUnitExplorerContext context)
{
- while (_frontierGeneral.Count > 0)
+ while (context.FrontierGeneral.Count > 0)
{
- var node = _frontierGeneral.PopFront()!;
- ExploreNode(node);
+ var node = context.FrontierGeneral.PopFront()!;
+ ExploreNode(context, node);
}
- while (_frontierMacros.Count > 0)
+ while (context.FrontierMacros.Count > 0)
{
- var node = _frontierMacros.PopFront()!;
- ExploreNode(node);
+ var node = context.FrontierMacros.PopFront()!;
+ ExploreNode(context, node);
}
}
- private void ExploreNode(ClangExplorerNode node)
+ private void ExploreNode(ClangTranslationUnitExplorerContext context, ClangTranslationUnitExplorerNode node)
{
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (node.Kind)
{
case CKind.TranslationUnit:
- ExploreTranslationUnit(node);
+ ExploreTranslationUnit(context, node);
break;
case CKind.Variable:
- ExploreVariable(node.Name!, node.TypeName!, node.Cursor, node.Type, node.Location, node.Parent!);
+ ExploreVariable(context, node.Name!, node.TypeName!, node.Cursor, node.Type, node.Location, node.Parent!);
break;
case CKind.Function:
- ExploreFunction(node.Name!, node.Cursor, node.Type, node.Location, node.Parent!);
+ ExploreFunction(context, node.Name!, node.Cursor, node.Type, node.Location, node.Parent!);
break;
case CKind.Typedef:
- ExploreTypedef(node, node.Parent!);
+ ExploreTypedef(context, node, node.Parent!);
break;
case CKind.OpaqueType:
- ExploreOpaqueType(node.TypeName!, node.Location);
+ ExploreOpaqueType(context, node.TypeName!, node.Location);
break;
case CKind.Enum:
- ExploreEnum(node.TypeName!, node.Cursor, node.Type, node.Location, node.Parent!);
+ ExploreEnum(context, node.TypeName!, node.Cursor, node.Type, node.Location, node.Parent!);
break;
case CKind.Record:
- ExploreRecord(node, node.Parent!);
+ ExploreRecord(context, node, node.Parent!);
break;
case CKind.FunctionPointer:
ExploreFunctionPointer(
- node.TypeName!, node.Cursor, node.Type, node.OriginalType, node.Location, node.Parent!);
+ context, node.TypeName!, node.Cursor, node.Type, node.Location, node.Parent!);
break;
case CKind.Array:
- ExploreArray(node);
+ VisitArray(context, node);
break;
case CKind.Pointer:
- ExplorePointer(node);
+ ExplorePointer(context, node);
break;
case CKind.Primitive:
break;
case CKind.MacroDefinition:
- ExploreMacro(node);
+ ExploreMacro(context, node);
break;
default:
var up = new UseCaseException($"Unexpected explorer node '{node.Kind}'.");
@@ -283,7 +156,7 @@ private void ExploreNode(ClangExplorerNode node)
}
}
- private bool IsIgnored(CXType type, CXCursor cursor)
+ private bool IsIgnored(ClangTranslationUnitExplorerContext context, CXType type, CXCursor cursor)
{
if (cursor.kind == CXCursorKind.CXCursor_TranslationUnit)
{
@@ -301,10 +174,10 @@ private bool IsIgnored(CXType type, CXCursor cursor)
if (kind == CKind.Array)
{
var elementType = clang_getElementType(actualType);
- return IsIgnored(elementType, cursor);
+ return IsIgnored(context, elementType, cursor);
}
- var fileLocation = kind == CKind.MacroDefinition ? Location(cursor) : Location(cursor, actualType);
+ var fileLocation = kind == CKind.MacroDefinition ? Location(context, cursor) : Location(context, cursor, actualType);
if (string.IsNullOrEmpty(fileLocation.FileName))
{
var up = new UseCaseException(
@@ -312,7 +185,7 @@ private bool IsIgnored(CXType type, CXCursor cursor)
throw up;
}
- foreach (var includeDirectory in _includeDirectories)
+ foreach (var includeDirectory in context.IncludeDirectories)
{
if (!fileLocation.FileName.Contains(includeDirectory, StringComparison.InvariantCulture))
{
@@ -324,15 +197,16 @@ private bool IsIgnored(CXType type, CXCursor cursor)
break;
}
- return _ignoredFiles.Contains(fileLocation.FileName);
+ return context.IgnoredFiles.Contains(fileLocation.FileName);
}
- private void ExploreTranslationUnit(ClangExplorerNode node)
+ private void ExploreTranslationUnit(
+ ClangTranslationUnitExplorerContext context, ClangTranslationUnitExplorerNode node)
{
var interestingCursors = node.Cursor.GetDescendents(IsCursorOfInterest);
foreach (var cursor in interestingCursors)
{
- VisitTranslationUnitCursor(node, cursor);
+ VisitTranslationUnitCursor(context, node, cursor);
}
static bool IsCursorOfInterest(CXCursor cursor, CXCursor cursorParent)
@@ -374,7 +248,8 @@ static bool IsCursorOfInterest(CXCursor cursor, CXCursor cursorParent)
}
}
- private void VisitTranslationUnitCursor(ClangExplorerNode parentNode, CXCursor cursor)
+ private void VisitTranslationUnitCursor(
+ ClangTranslationUnitExplorerContext context, ClangTranslationUnitExplorerNode parentNode, CXCursor cursor)
{
var kind = cursor.kind switch
{
@@ -396,16 +271,16 @@ private void VisitTranslationUnitCursor(ClangExplorerNode parentNode, CXCursor c
if (kind == CKind.MacroDefinition)
{
- var location = Location(cursor);
- AddExplorerNode(kind, location, parentNode, cursor, default, default, name, string.Empty);
+ var location = Location(context, cursor);
+ AddExplorerNode(context, kind, location, parentNode, cursor, default, name, string.Empty);
}
else
{
var type = clang_getCursorType(cursor);
- var location = Location(cursor, type);
+ var location = Location(context, cursor, type);
var typeName = TypeName(parentNode.TypeName!, kind, type, cursor);
- var isIgnored = IsIgnored(type, cursor);
+ var isIgnored = IsIgnored(context, type, cursor);
if (isIgnored)
{
return;
@@ -413,53 +288,68 @@ private void VisitTranslationUnitCursor(ClangExplorerNode parentNode, CXCursor c
if (kind == CKind.Enum)
{
- ExploreEnum(typeName, cursor, type, location, parentNode, true);
+ ExploreEnum(context, typeName, cursor, type, location, parentNode);
}
else
{
- AddExplorerNode(kind, location, parentNode, cursor, type, type, name, typeName);
+ AddExplorerNode(context, kind, location, parentNode, cursor, type, name, typeName);
}
}
}
- private void ExploreArray(ClangExplorerNode node)
+ private void VisitArray(
+ ClangTranslationUnitExplorerContext context, ClangTranslationUnitExplorerNode node)
{
var elementType = clang_getElementType(node.Type);
var (kind, type) = TypeKind(elementType);
var typeCursor = clang_getTypeDeclaration(type);
var cursor = typeCursor.kind == CXCursorKind.CXCursor_NoDeclFound ? node.Cursor : typeCursor;
var typeName = TypeName(node.TypeName!, kind, type, typeCursor);
- VisitType(node, cursor, node.Cursor, type, type, typeName);
+ VisitType(context, node, cursor, node.Cursor, type, typeName);
}
- private void ExplorePointer(ClangExplorerNode node)
+ private void ExplorePointer(
+ ClangTranslationUnitExplorerContext context, ClangTranslationUnitExplorerNode node)
{
var pointeeType = clang_getPointeeType(node.Type);
var (kind, type) = TypeKind(pointeeType);
var typeCursor = clang_getTypeDeclaration(type);
var typeName = TypeName(node.TypeName!, kind, type, typeCursor);
- VisitType(node, typeCursor, typeCursor, type, type, typeName);
+ VisitType(context, node, typeCursor, typeCursor, type, typeName);
}
- private void ExploreMacro(ClangExplorerNode node)
+ private void ExploreMacro(ClangTranslationUnitExplorerContext context, ClangTranslationUnitExplorerNode node)
{
var name = node.Name!;
+ if (context.Names.Contains(name))
+ {
+ var diagnostic = new MacroAlreadyExistsDiagnostic(name);
+ context.Diagnostics.Add(diagnostic);
+ return;
+ }
+
var location = node.Location;
// Function-like macros currently not implemented
// https://github.com/lithiumtoast/c2cs/issues/35
if (clang_Cursor_isMacroFunctionLike(node.Cursor) != 0)
{
- _macroFunctionLikeNames.Add(name);
+ context.MacroFunctionLikeNames.Add(name);
return;
}
- // It is assumed that macros with a name which starts with an underscore are not supposed to be exposed in the public API
+ // Assume that macros with a name which starts with an underscore are not supposed to be exposed in the public API
if (name.StartsWith("_", StringComparison.InvariantCulture))
{
return;
}
+ // Assume that macro ending with "API_DECL" are not interesting for bindgen
+ if (name.EndsWith("API_DECL", StringComparison.InvariantCulture))
+ {
+ return;
+ }
+
// libclang doesn't have a thing where we can easily get a value of a macro
// we need to:
// 1. get the text range of the cursor
@@ -505,12 +395,13 @@ private void ExploreMacro(ClangExplorerNode node)
// Ignore macros with certain tokens
foreach (var token in tokens)
{
- if (_macroFunctionLikeNames.Contains(token))
+ if (context.MacroFunctionLikeNames.Contains(token))
{
return;
}
- if (_ignoredMacroTokens.Contains(token))
+ // cinttypes.h
+ if (token.StartsWith("PRI", StringComparison.InvariantCulture))
{
return;
}
@@ -536,11 +427,25 @@ private void ExploreMacro(ClangExplorerNode node)
}
// Ignore macros which are forward declarations
- if (tokens.Length == 1 && _names.Contains(tokens[0]))
+ if (tokens.Length == 1 && context.Names.Contains(tokens[0]))
{
return;
}
+ if (name == "C2CS_RUNTIME_TARGET_PLATFORM_NAME")
+ {
+ var actualPlatformName = tokens.Length != 1 ? string.Empty : tokens[0].Replace("\"", string.Empty, StringComparison.InvariantCulture);
+ var actualPlatform = new TargetPlatform(actualPlatformName);
+ var expectedPlatform = context.TargetPlatform;
+ if (actualPlatform != expectedPlatform)
+ {
+ var diagnostic = new PlatformMismatchDiagnostic(actualPlatform, expectedPlatform);
+ context.Diagnostics.Add(diagnostic);
+ }
+
+ return;
+ }
+
var macro = new CMacroDefinition
{
Name = name,
@@ -548,18 +453,23 @@ private void ExploreMacro(ClangExplorerNode node)
Location = location
};
- _macroObjects.Add(macro);
+ context.Names.Add(name);
+ context.MacroObjects.Add(macro);
+ _logger.ExploreCodeMacro(name);
}
private void ExploreVariable(
+ ClangTranslationUnitExplorerContext context,
string name,
string typeName,
CXCursor cursor,
CXType type,
- ClangLocation location,
- ClangExplorerNode parentNode)
+ CLocation location,
+ ClangTranslationUnitExplorerNode parentNode)
{
- VisitType(parentNode, cursor, cursor, type, type, typeName);
+ _logger.ExploreCodeVariable(name);
+
+ VisitType(context, parentNode, cursor, cursor, type, typeName);
var variable = new CVariable
{
@@ -568,30 +478,33 @@ private void ExploreVariable(
Type = typeName
};
- _variables.Add(variable);
- _names.Add(name);
+ context.Variables.Add(variable);
+ context.Names.Add(name);
}
private void ExploreFunction(
+ ClangTranslationUnitExplorerContext context,
string name,
CXCursor cursor,
CXType type,
- ClangLocation location,
- ClangExplorerNode parentNode)
+ CLocation location,
+ ClangTranslationUnitExplorerNode parentNode)
{
- if (!_functionNamesWhitelist.IsEmpty && !_functionNamesWhitelist.Contains(name))
+ if (!context.FunctionNamesWhitelist.IsEmpty && !context.FunctionNamesWhitelist.Contains(name))
{
return;
}
+ _logger.ExploreCodeFunction(name);
+
var callingConvention = CreateFunctionCallingConvention(type);
var resultType = clang_getCursorResultType(cursor);
var (kind, actualType) = TypeKind(resultType);
var resultTypeName = TypeName(parentNode.TypeName!, kind, actualType, cursor);
- VisitType(parentNode, cursor, cursor, resultType, resultType, resultTypeName);
+ VisitType(context, parentNode, cursor, cursor, resultType, resultTypeName);
- var parameters = CreateFunctionParameters(cursor, parentNode);
+ var functionParameters = CreateFunctionParameters(context, cursor, parentNode);
var function = new CFunction
{
@@ -599,21 +512,28 @@ private void ExploreFunction(
Location = location,
CallingConvention = callingConvention,
ReturnType = resultTypeName,
- Parameters = parameters
+ Parameters = functionParameters
};
- _functions.Add(function);
- _names.Add(function.Name);
+ context.Functions.Add(function);
+ context.Names.Add(function.Name);
}
private void ExploreEnum(
+ ClangTranslationUnitExplorerContext context,
string typeName,
CXCursor cursor,
CXType type,
- ClangLocation location,
- ClangExplorerNode parentNode,
- bool isPseudo = false)
+ CLocation location,
+ ClangTranslationUnitExplorerNode parentNode)
{
+ if (context.Names.Contains(typeName))
+ {
+ return;
+ }
+
+ _logger.ExploreCodeEnum(typeName);
+
var typeCursor = clang_getTypeDeclaration(type);
if (typeCursor.kind == CXCursorKind.CXCursor_NoDeclFound)
{
@@ -623,9 +543,9 @@ private void ExploreEnum(
var integerType = clang_getEnumDeclIntegerType(typeCursor);
var integerTypeName = TypeName(parentNode.TypeName!, CKind.Enum, integerType, cursor);
- VisitType(parentNode, cursor, cursor, integerType, integerType, integerTypeName);
+ VisitType(context, parentNode, cursor, cursor, integerType, integerTypeName);
- var enumValues = CreateEnumValues(typeCursor);
+ var enumValues = CreateEnumValues(context, typeCursor);
var @enum = new CEnum
{
@@ -636,33 +556,28 @@ private void ExploreEnum(
Values = enumValues
};
- if (isPseudo)
- {
- _pseudoEnums.Add(@enum);
- }
- else
- {
- _enums.Add(@enum);
- }
-
- _names.Add(@enum.Name);
+ context.Enums.Add(@enum);
+ context.Names.Add(@enum.Name);
}
- private void ExploreRecord(ClangExplorerNode node, ClangExplorerNode parentNode)
+ private void ExploreRecord(
+ ClangTranslationUnitExplorerContext context, ClangTranslationUnitExplorerNode node, ClangTranslationUnitExplorerNode parentNode)
{
var typeName = node.TypeName!;
var location = node.Location;
- if (_opaqueTypeNames.Contains(typeName))
+ if (context.OpaqueTypesNames.Contains(typeName))
{
- ExploreOpaqueType(typeName, location);
+ ExploreOpaqueType(context, typeName, location);
return;
}
+ _logger.ExploreCodeRecord(typeName);
+
var cursor = node.Cursor;
- var fields = CreateRecordFields(typeName, cursor, parentNode);
- var nestedNodes = CreateNestedNodes(typeName, cursor, node);
+ var fields = CreateRecordFields(context, typeName, cursor, parentNode);
+ var nestedNodes = CreateNestedNodes(context, typeName, cursor, node);
var nestedRecords = nestedNodes.Where(x => x is CRecord).Cast().ToImmutableArray();
@@ -687,23 +602,24 @@ private void ExploreRecord(ClangExplorerNode node, ClangExplorerNode parentNode)
return;
}
- _records.Add(record);
- _names.Add(record.Name);
+ context.Records.Add(record);
+ context.Names.Add(record.Name);
}
private void ExploreTypedef(
- ClangExplorerNode node, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ ClangTranslationUnitExplorerNode node,
+ ClangTranslationUnitExplorerNode parentNode)
{
var typeName = node.TypeName!;
var location = node.Location;
- if (_opaqueTypeNames.Contains(typeName))
+ if (context.OpaqueTypesNames.Contains(typeName))
{
- ExploreOpaqueType(typeName, location);
+ ExploreOpaqueType(context, typeName, location);
return;
}
- var type = node.Type;
var underlyingType = clang_getTypedefDeclUnderlyingType(node.Cursor);
var (aliasKind, aliasType) = TypeKind(underlyingType);
var aliasCursor = clang_getTypeDeclaration(aliasType);
@@ -712,18 +628,20 @@ private void ExploreTypedef(
switch (aliasKind)
{
case CKind.Enum:
- ExploreEnum(typeName, cursor, aliasType, location, parentNode);
+ ExploreEnum(context, typeName, cursor, aliasType, location, parentNode);
return;
case CKind.Record:
- ExploreRecord(node, parentNode);
+ ExploreRecord(context, node, parentNode);
return;
case CKind.FunctionPointer:
- ExploreFunctionPointer(typeName, cursor, aliasType, type, location, parentNode);
+ ExploreFunctionPointer(context, typeName, cursor, aliasType, location, parentNode);
return;
}
+ _logger.ExploreCodeTypedef(typeName);
+
var aliasTypeName = TypeName(parentNode.TypeName!, aliasKind, aliasType, cursor);
- VisitType(parentNode, cursor, node.Cursor, aliasType, aliasType, aliasTypeName);
+ VisitType(context, parentNode, cursor, node.Cursor, aliasType, aliasTypeName);
var typedef = new CTypedef
{
@@ -732,76 +650,77 @@ private void ExploreTypedef(
UnderlyingType = aliasTypeName
};
- _typedefs.Add(typedef);
- _names.Add(typedef.Name);
+ context.Typedefs.Add(typedef);
+ context.Names.Add(typedef.Name);
}
- private void ExploreOpaqueType(string typeName, ClangLocation location)
+ private void ExploreOpaqueType(ClangTranslationUnitExplorerContext context, string typeName, CLocation location)
{
+ _logger.ExploreCodeOpaqueType(typeName);
+
var opaqueDataType = new COpaqueType
{
Name = typeName,
Location = location
};
- _opaqueDataTypes.Add(opaqueDataType);
- _names.Add(opaqueDataType.Name);
+ context.OpaqueDataTypes.Add(opaqueDataType);
+ context.Names.Add(opaqueDataType.Name);
}
private void ExploreFunctionPointer(
+ ClangTranslationUnitExplorerContext context,
string typeName,
CXCursor cursor,
CXType type,
- CXType originalType,
- ClangLocation location,
- ClangExplorerNode parentNode)
+ CLocation location,
+ ClangTranslationUnitExplorerNode parentNode)
{
+ _logger.ExploreCodeFunctionPointer(typeName);
+
if (type.kind == CXTypeKind.CXType_Pointer)
{
type = clang_getPointeeType(type);
}
- var functionPointer = CreateFunctionPointer(typeName, cursor, parentNode, originalType, type, location);
+ var functionPointer = CreateFunctionPointer(context, typeName, cursor, parentNode, type, location);
- _functionPointers.Add(functionPointer);
- _names.Add(functionPointer.Name);
+ context.FunctionPointers.Add(functionPointer);
+ context.Names.Add(functionPointer.Name);
}
- private bool TypeNameIsValid(CXType type, string typeName)
+ private bool TypeNameIsValid(ClangTranslationUnitExplorerContext context, string typeName)
{
- if (_validTypeNames.TryGetValue(typeName, out var value))
+ if (context.ValidTypeNames.TryGetValue(typeName, out var isValid))
{
- return value;
+ return isValid;
}
- var isSystem = type.IsSystem();
- var isIgnored = _systemIgnoredTypeNames.Contains(typeName);
- if (isSystem && isIgnored)
- {
- value = false;
- }
- else
- {
- value = true;
- }
+ var isIgnored = context.SystemIgnoredTypeNames.Contains(typeName);
+ isValid = !isIgnored;
- _validTypeNames.Add(typeName, value);
- return value;
+ context.ValidTypeNames.Add(typeName, isValid);
+ return isValid;
}
- private bool RegisterTypeIsNew(string typeName, CXType type, CXCursor cursor)
+ private bool IsNewType(ClangTranslationUnitExplorerContext context, string typeName, CXType type, CXCursor cursor)
{
if (string.IsNullOrEmpty(typeName))
{
- return true;
+ return false;
}
- var alreadyVisited = _typesByName.TryGetValue(typeName, out var typeC);
+ var alreadyVisited = context.TypesByName.TryGetValue(typeName, out var typeC);
if (alreadyVisited)
{
+ if (typeC == null)
+ {
+ return false;
+ }
+
// attempt to see if we have a definition for a previous opaque type, to which we should that info instead
// this can happen if one header file has a forward type, but another header file has the definition
- if (typeC!.Kind != CKind.OpaqueType)
+ if (typeC.Kind != CKind.OpaqueType)
{
return false;
}
@@ -812,26 +731,25 @@ private bool RegisterTypeIsNew(string typeName, CXType type, CXCursor cursor)
return false;
}
- typeC = Type(typeName, cursor, type);
- _typesByName[typeName] = typeC;
+ typeC = Type(context, typeName, cursor, type);
+ context.TypesByName[typeName] = typeC;
return true;
}
- typeC = Type(typeName, cursor, type);
-
- _typesByName.Add(typeName, typeC);
- _types.Add(typeC);
+ typeC = Type(context, typeName, cursor, type);
+ context.TypesByName.Add(typeName, typeC);
+ context.Types.Add(typeC);
return true;
}
private void AddExplorerNode(
+ ClangTranslationUnitExplorerContext context,
CKind kind,
- ClangLocation location,
- ClangExplorerNode? parent,
+ CLocation location,
+ ClangTranslationUnitExplorerNode? parent,
CXCursor cursor,
CXType type,
- CXType originalType,
string name,
string typeName)
{
@@ -843,29 +761,28 @@ private void AddExplorerNode(
throw up;
}
- var isIgnored = IsIgnored(type, cursor);
+ var isIgnored = IsIgnored(context, type, cursor);
if (isIgnored)
{
return;
}
- var node = new ClangExplorerNode(
+ var node = new ClangTranslationUnitExplorerNode(
kind,
location,
parent,
cursor,
type,
- originalType,
name,
typeName);
if (kind == CKind.MacroDefinition)
{
- _frontierMacros.PushBack(node);
+ context.FrontierMacros.PushBack(node);
}
else
{
- _frontierGeneral.PushBack(node);
+ context.FrontierGeneral.PushBack(node);
}
}
@@ -883,7 +800,9 @@ private static CFunctionCallingConvention CreateFunctionCallingConvention(CXType
}
private ImmutableArray CreateFunctionParameters(
- CXCursor cursor, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ CXCursor cursor,
+ ClangTranslationUnitExplorerNode parentNode)
{
var builder = ImmutableArray.CreateBuilder();
@@ -892,7 +811,7 @@ private ImmutableArray CreateFunctionParameters(
foreach (var parameterCursor in parameterCursors)
{
- var functionExternParameter = FunctionParameter(parameterCursor, parentNode);
+ var functionExternParameter = FunctionParameter(context, parameterCursor, parentNode);
builder.Add(functionExternParameter);
}
@@ -900,7 +819,8 @@ private ImmutableArray CreateFunctionParameters(
return result;
}
- private CFunctionParameter FunctionParameter(CXCursor cursor, ClangExplorerNode parentNode)
+ private CFunctionParameter FunctionParameter(
+ ClangTranslationUnitExplorerContext context, CXCursor cursor, ClangTranslationUnitExplorerNode parentNode)
{
var type = clang_getCursorType(cursor);
var name = cursor.Name();
@@ -908,8 +828,8 @@ private CFunctionParameter FunctionParameter(CXCursor cursor, ClangExplorerNode
var (kind, typeActual) = TypeKind(type);
var typeName = TypeName(parentNode.TypeName!, kind, typeActual, cursor);
- VisitType(parentNode, cursor, cursor, type, type, typeName);
- var codeLocation = Location(cursor, type);
+ VisitType(context, parentNode, cursor, cursor, type, typeName);
+ var codeLocation = Location(context, cursor, type);
return new CFunctionParameter
{
@@ -920,19 +840,19 @@ private CFunctionParameter FunctionParameter(CXCursor cursor, ClangExplorerNode
}
private CFunctionPointer CreateFunctionPointer(
+ ClangTranslationUnitExplorerContext context,
string typeName,
CXCursor cursor,
- ClangExplorerNode parentNode,
- CXType originalType,
+ ClangTranslationUnitExplorerNode parentNode,
CXType type,
- ClangLocation location)
+ CLocation location)
{
- var parameters = CreateFunctionPointerParameters(cursor, parentNode);
+ var functionPointerParameters = CreateFunctionPointerParameters(context, cursor, parentNode);
var returnType = clang_getResultType(type);
var (kind, actualReturnType) = TypeKind(returnType);
var returnTypeName = TypeName(parentNode.TypeName!, kind, actualReturnType, cursor);
- VisitType(parentNode, cursor, cursor, returnType, returnType, returnTypeName);
+ VisitType(context, parentNode, cursor, cursor, returnType, returnTypeName);
var name = string.Empty;
if (cursor.kind == CXCursorKind.CXCursor_TypedefDecl)
@@ -950,14 +870,16 @@ private CFunctionPointer CreateFunctionPointer(
Location = location,
Type = typeName,
ReturnType = returnTypeName,
- Parameters = parameters
+ Parameters = functionPointerParameters
};
return functionPointer;
}
private ImmutableArray CreateFunctionPointerParameters(
- CXCursor cursor, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ CXCursor cursor,
+ ClangTranslationUnitExplorerNode parentNode)
{
var builder = ImmutableArray.CreateBuilder();
@@ -966,7 +888,7 @@ private ImmutableArray CreateFunctionPointerParameter
foreach (var parameterCursor in parameterCursors)
{
- var functionPointerParameter = CreateFunctionPointerParameter(parameterCursor, parentNode);
+ var functionPointerParameter = CreateFunctionPointerParameter(context, parameterCursor, parentNode);
builder.Add(functionPointerParameter);
}
@@ -975,16 +897,18 @@ private ImmutableArray CreateFunctionPointerParameter
}
private CFunctionPointerParameter CreateFunctionPointerParameter(
- CXCursor cursor, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ CXCursor cursor,
+ ClangTranslationUnitExplorerNode parentNode)
{
var type = clang_getCursorType(cursor);
- var codeLocation = Location(cursor, type);
+ var codeLocation = Location(context, cursor, type);
var name = cursor.Name();
var (kind, actualType) = TypeKind(type);
var typeName = TypeName(parentNode.TypeName!, kind, actualType, cursor);
- VisitType(parentNode, cursor, cursor, type, type, typeName);
+ VisitType(context, parentNode, cursor, cursor, type, typeName);
return new CFunctionPointerParameter
{
@@ -995,7 +919,10 @@ private CFunctionPointerParameter CreateFunctionPointerParameter(
}
private ImmutableArray CreateRecordFields(
- string recordName, CXCursor cursor, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ string recordName,
+ CXCursor cursor,
+ ClangTranslationUnitExplorerNode parentNode)
{
var builder = ImmutableArray.CreateBuilder();
@@ -1014,17 +941,18 @@ private ImmutableArray CreateRecordFields(
foreach (var fieldCursor in fieldCursors)
{
- var recordField = CreateRecordField(recordName, fieldCursor, parentNode);
+ var recordField = CreateRecordField(context, recordName, fieldCursor, parentNode);
builder.Add(recordField);
}
- CalculatePaddingForStructFields(cursor, builder);
+ CalculatePaddingForStructFields(context, cursor, builder);
var result = builder.ToImmutable();
return result;
}
private void CalculatePaddingForStructFields(
+ ClangTranslationUnitExplorerContext context,
CXCursor cursor,
ImmutableArray.Builder builder)
{
@@ -1033,7 +961,7 @@ private void CalculatePaddingForStructFields(
var recordField = builder[i];
var fieldPrevious = builder[i - 1];
var typeName = Value(fieldPrevious.Type);
- var type = _typesByName[typeName];
+ var type = context.TypesByName[typeName];
var fieldPreviousTypeSizeOf = type.SizeOf;
var expectedFieldOffset = fieldPrevious.Offset + fieldPreviousTypeSizeOf;
var hasPadding = recordField.Offset != 0 && recordField.Offset != expectedFieldOffset;
@@ -1052,7 +980,7 @@ private void CalculatePaddingForStructFields(
var cursorType = clang_getCursorType(cursor);
var recordSize = (int)clang_Type_getSizeOf(cursorType);
var typeName = Value(fieldLast.Type);
- var type = _typesByName[typeName];
+ var type = context.TypesByName[typeName];
var fieldLastTypeSize = type.SizeOf;
var expectedLastFieldOffset = recordSize - fieldLastTypeSize;
if (fieldLast.Offset != expectedLastFieldOffset)
@@ -1076,15 +1004,18 @@ private string Value(string typeName)
}
private CRecordField CreateRecordField(
- string recordName, CXCursor cursor, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ string recordName,
+ CXCursor cursor,
+ ClangTranslationUnitExplorerNode parentNode)
{
var name = cursor.Name();
var type = clang_getCursorType(cursor);
- var codeLocation = Location(cursor, type);
+ var codeLocation = Location(context, cursor, type);
var (kind, actualType) = TypeKind(type);
var typeName = TypeName(recordName, kind, actualType, cursor);
- VisitType(parentNode, cursor, cursor, type, type, typeName);
+ VisitType(context, parentNode, cursor, cursor, type, typeName);
var offset = (int)(clang_Cursor_getOffsetOfField(cursor) / 8);
@@ -1098,7 +1029,10 @@ private CRecordField CreateRecordField(
}
private ImmutableArray CreateNestedNodes(
- string parentTypeName, CXCursor cursor, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ string parentTypeName,
+ CXCursor cursor,
+ ClangTranslationUnitExplorerNode parentNode)
{
var builder = ImmutableArray.CreateBuilder();
@@ -1131,7 +1065,7 @@ private ImmutableArray CreateNestedNodes(
foreach (var nestedCursor in nestedCursors)
{
- var record = CreateNestedNode(parentTypeName, nestedCursor, parentNode);
+ var record = CreateNestedNode(context, parentTypeName, nestedCursor, parentNode);
builder.Add(record);
}
@@ -1144,21 +1078,24 @@ private ImmutableArray CreateNestedNodes(
}
private CNode CreateNestedNode(
- string parentTypeName, CXCursor cursor, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ string parentTypeName,
+ CXCursor cursor,
+ ClangTranslationUnitExplorerNode parentNode)
{
var type = clang_getCursorType(cursor);
var isPointer = type.kind == CXTypeKind.CXType_Pointer;
if (!isPointer)
{
- return CreateNestedStruct(parentTypeName, cursor, type, parentNode);
+ return CreateNestedStruct(context, parentTypeName, cursor, type, parentNode);
}
var pointeeType = clang_getPointeeType(type);
if (pointeeType.kind == CXTypeKind.CXType_FunctionProto)
{
var typeName = TypeName(parentTypeName, CKind.FunctionPointer, pointeeType, cursor);
- var location = Location(cursor, type);
- return CreateFunctionPointer(typeName, cursor, parentNode, type, pointeeType, location);
+ var location = Location(context, cursor, type);
+ return CreateFunctionPointer(context, typeName, cursor, parentNode, pointeeType, location);
}
var up = new UseCaseException("Unknown mapping for nested node.");
@@ -1166,13 +1103,17 @@ private CNode CreateNestedNode(
}
private CNode CreateNestedStruct(
- string parentTypeName, CXCursor cursor, CXType type, ClangExplorerNode parentNode)
+ ClangTranslationUnitExplorerContext context,
+ string parentTypeName,
+ CXCursor cursor,
+ CXType type,
+ ClangTranslationUnitExplorerNode parentNode)
{
- var location = Location(cursor, type);
+ var location = Location(context, cursor, type);
var typeName = TypeName(parentTypeName, CKind.Record, type, cursor);
- var recordFields = CreateRecordFields(typeName, cursor, parentNode);
- var nestedNodes = CreateNestedNodes(typeName, cursor, parentNode);
+ var recordFields = CreateRecordFields(context, typeName, cursor, parentNode);
+ var nestedNodes = CreateNestedNodes(context, typeName, cursor, parentNode);
var nestedRecords = nestedNodes.Where(x => x is CRecord).Cast().ToImmutableArray();
var typeCursor = clang_getTypeDeclaration(type);
@@ -1188,7 +1129,7 @@ private CNode CreateNestedStruct(
};
}
- private ImmutableArray CreateEnumValues(CXCursor cursor)
+ private ImmutableArray CreateEnumValues(ClangTranslationUnitExplorerContext context, CXCursor cursor)
{
var builder = ImmutableArray.CreateBuilder();
@@ -1217,18 +1158,16 @@ private ImmutableArray CreateEnumValues(CXCursor cursor)
private CEnumValue CreateEnumValue(CXCursor cursor, string? name = null)
{
var value = clang_getEnumConstantDeclValue(cursor);
- var location = Location(cursor);
name ??= cursor.Name();
return new CEnumValue
{
- Location = location,
Name = name,
Value = value
};
}
- private CType Type(string typeName, CXCursor cursor, CXType clangType)
+ private CType Type(ClangTranslationUnitExplorerContext context, string typeName, CXCursor cursor, CXType clangType)
{
var type = clangType;
var declaration = clang_getTypeDeclaration(type);
@@ -1237,70 +1176,47 @@ private CType Type(string typeName, CXCursor cursor, CXType clangType)
declaration = cursor;
}
- // if (type.kind == CXTypeKind.CXType_IncompleteArray)
- // {
- // var elementType = clang_getElementType(type);
- // if (elementType.kind == CXTypeKind.CXType_Typedef)
- // {
- // var elementCursor = clang_getTypeDeclaration(elementType);
- // var underlyingCursor = ClangUnderlyingCursor(elementCursor);
- // elementType = clang_getTypedefDeclUnderlyingType(x);
- // }
- //
- // if (elementType.kind == CXTypeKind.CXType_Pointer)
- // {
- // sizeOfValue = (int)clang_Type_getSizeOf(elementType);
- // }
- // }
-
- var sizeOf = SizeOf(type);
+ var sizeOf = SizeOf(context, type);
var alignOfValue = (int)clang_Type_getAlignOf(type);
int? alignOf = alignOfValue >= 0 ? alignOfValue : null;
var arraySizeValue = (int)clang_getArraySize(type);
int? arraySize = arraySizeValue >= 0 ? arraySizeValue : null;
var isSystemType = type.IsSystem();
+ var (kind, kindType) = TypeKind(type);
+
int? elementSize = null;
- if (type.kind == CXTypeKind.CXType_ConstantArray)
+ if (kind == CKind.Array)
{
- var elementType = clang_getElementType(type);
+ var (_, arrayType) = TypeKind(kindType);
+ var elementType = clang_getElementType(arrayType);
elementSize = (int)clang_Type_getSizeOf(elementType);
}
- ClangLocation? location = null;
-
- var typeKind = TypeKind(type);
- if (typeKind.Kind != CKind.Primitive && !isSystemType)
- {
- location = Location(declaration, type);
- }
+ var location = Location(context, declaration, type);
var cType = new CType
{
Name = typeName,
- Kind = typeKind.Kind,
+ Kind = kind,
SizeOf = sizeOf,
AlignOf = alignOf,
ElementSize = elementSize,
ArraySize = arraySize,
- IsSystem = isSystemType,
Location = location
};
- if (location != null)
+ var fileName = location.FileName;
+ if (context.IgnoredFiles.Contains(fileName))
{
- var fileName = location.Value.FileName;
- if (_ignoredFiles.Contains(fileName))
- {
- var diagnostic = new TypeFromIgnoredHeaderDiagnostic(typeName, fileName);
- _diagnostics.Add(diagnostic);
- }
+ var diagnostic = new TypeFromIgnoredHeaderDiagnostic(typeName, fileName);
+ context.Diagnostics.Add(diagnostic);
}
return cType;
}
- private int SizeOf(CXType type)
+ private int SizeOf(ClangTranslationUnitExplorerContext context, CXType type)
{
var sizeOf = (int)clang_Type_getSizeOf(type);
if (sizeOf >= 0)
@@ -1330,7 +1246,7 @@ private int SizeOf(CXType type)
case CKind.Pointer:
return (int)clang_Type_getSizeOf(underlyingType);
default:
- var location = Location(clang_getTypeDeclaration(type), type);
+ var location = Location(context, clang_getTypeDeclaration(type), type);
throw new UseCaseException(
$"Unexpected case when determining size for Clang type: {location}. Please submit an issue on GitHub!");
}
@@ -1438,11 +1354,11 @@ private static CXCursor ClangUnderlyingCursor(CXCursor cursor)
}
private void VisitType(
- ClangExplorerNode parentNode,
+ ClangTranslationUnitExplorerContext context,
+ ClangTranslationUnitExplorerNode parentNode,
CXCursor cursor,
CXCursor originalCursor,
CXType type,
- CXType originalType,
string typeName)
{
if (cursor.kind == CXCursorKind.CXCursor_NoDeclFound)
@@ -1450,55 +1366,49 @@ private void VisitType(
throw new UseCaseException("NoDecl cursor.");
}
- if (!RegisterTypeIsNew(typeName, type, cursor))
+ if (!IsNewType(context, typeName, type, cursor))
{
return;
}
- var isValidTypeName = TypeNameIsValid(type, typeName);
+ var isValidTypeName = TypeNameIsValid(context, typeName);
if (!isValidTypeName)
{
return;
}
- var typeKind = TypeKind(type);
- if (typeKind.Kind == CKind.Pointer)
+ var (kind, kindType) = TypeKind(type);
+ if (kind == CKind.Typedef)
{
- var pointeeType = clang_getPointeeType(typeKind.Type);
- var pointeeKind = TypeKind(pointeeType);
+ VisitTypedef(context, parentNode, kindType, typeName);
+ return;
+ }
+
+ _logger.ExploreCodeVisitType(typeName);
+
+ if (kind == CKind.Pointer)
+ {
+ var pointeeType = clang_getPointeeType(kindType);
+ var (pointeeKind, pointeeKindType) = TypeKind(pointeeType);
var pointeeCursor = clang_getTypeDeclaration(pointeeType);
var pointeeCursor2 = pointeeCursor.kind == CXCursorKind.CXCursor_NoDeclFound ? cursor : pointeeCursor;
- var pointeeTypeName = TypeName(parentNode.TypeName!, pointeeKind.Kind, pointeeKind.Type, pointeeCursor2);
+ var pointeeTypeName = TypeName(parentNode.TypeName!, pointeeKind, pointeeKindType, pointeeCursor2);
VisitType(
+ context,
parentNode,
pointeeCursor2,
originalCursor,
- pointeeKind.Type,
- type,
+ pointeeKindType,
pointeeTypeName);
- return;
- }
-
- if (typeKind.Kind == CKind.Typedef)
- {
- VisitTypedef(parentNode, typeKind.Type, typeName);
}
else
{
- CXType locationType;
- if (type.kind == CXTypeKind.CXType_IncompleteArray ||
- type.kind == CXTypeKind.CXType_ConstantArray)
- {
- locationType = clang_getElementType(type);
- }
- else if (type.kind == CXTypeKind.CXType_Pointer)
- {
- locationType = clang_getPointeeType(type);
- }
- else
+ var locationType = type.kind switch
{
- locationType = type;
- }
+ CXTypeKind.CXType_IncompleteArray or CXTypeKind.CXType_ConstantArray => clang_getElementType(type),
+ CXTypeKind.CXType_Pointer => clang_getPointeeType(type),
+ _ => type
+ };
var locationCursor = clang_getTypeDeclaration(locationType);
if (locationCursor.kind == CXCursorKind.CXCursor_NoDeclFound)
@@ -1511,24 +1421,25 @@ private void VisitType(
locationCursor = originalCursor;
}
- var location = Location(locationCursor);
+ var location = Location(context, locationCursor);
AddExplorerNode(
- typeKind.Kind,
+ context,
+ kind,
location,
parentNode,
cursor,
- typeKind.Type,
- originalType,
+ kindType,
string.Empty,
typeName);
}
}
- private void VisitTypedef(ClangExplorerNode parentNode, CXType type, string typeName)
+ private void VisitTypedef(
+ ClangTranslationUnitExplorerContext context, ClangTranslationUnitExplorerNode parentNode, CXType type, string typeName)
{
var typedefCursor = clang_getTypeDeclaration(type);
- var location = Location(typedefCursor);
- AddExplorerNode(CKind.Typedef, location, parentNode, typedefCursor, type, type, string.Empty, typeName);
+ var location = Location(context, typedefCursor);
+ AddExplorerNode(context, CKind.Typedef, location, parentNode, typedefCursor, type, string.Empty, typeName);
}
private string TypeName(string? parentTypeName, CKind kind, CXType type, CXCursor cursor)
@@ -1570,11 +1481,7 @@ private string TypeName(string? parentTypeName, CKind kind, CXType type, CXCurso
_ => throw new UseCaseException($"Unexpected node kind '{kind}'.")
};
- if (type.kind == CXTypeKind.CXType_IncompleteArray)
- {
- typeName = $"{typeName}";
- }
- else if (type.kind == CXTypeKind.CXType_ConstantArray)
+ if (type.kind == CXTypeKind.CXType_ConstantArray)
{
var arraySize = clang_getArraySize(type);
typeName = $"{typeName}[{arraySize}]";
@@ -1585,31 +1492,12 @@ private string TypeName(string? parentTypeName, CKind kind, CXType type, CXCurso
throw new UseCaseException($"Type name was not found for '{kind}'.");
}
- if (kind == CKind.Enum)
- {
- typeName = typeName switch
- {
- // TRICK: Force signed integer; enums in C could be signed or unsigned depending the platform architecture.
- // This makes for a slightly different bindings between Windows/macOS/Linux where the enum is different type
- "unsigned char" or "char" => "signed char",
- "short" or "unsigned short" => "signed short",
- "short int" or "unsigned short int" => "signed short int",
- "unsigned" => "signed",
- "int" or "unsigned int" => "signed int",
- "long" or "unsigned long" => "signed long",
- "long int" or "unsigned long int" => "signed long int",
- "long long" or "unsigned long long" => "signed long long",
- "long long int" or "unsigned long long int" => "signed long long int",
- _ => typeName
- };
- }
-
return typeName;
}
- private ClangLocation Location(CXCursor cursor, CXType? type = null)
+ private CLocation Location(ClangTranslationUnitExplorerContext context, CXCursor cursor, CXType? type = null)
{
- ClangLocation location;
+ CLocation location;
if (type == null)
{
location = cursor.FileLocation();
@@ -1623,13 +1511,16 @@ private ClangLocation Location(CXCursor cursor, CXType? type = null)
}
}
- foreach (var includeDirectory in _includeDirectories)
+ if (!string.IsNullOrEmpty(location.FilePath))
{
- if (location.FilePath.Contains(includeDirectory, StringComparison.InvariantCulture))
+ foreach (var includeDirectory in context.IncludeDirectories)
{
- location.FilePath = location.FilePath
- .Replace(includeDirectory, string.Empty, StringComparison.InvariantCulture).Trim('/', '\\');
- break;
+ if (location.FilePath.Contains(includeDirectory, StringComparison.InvariantCulture))
+ {
+ location.FilePath = location.FilePath
+ .Replace(includeDirectory, string.Empty, StringComparison.InvariantCulture).Trim('/', '\\');
+ break;
+ }
}
}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorerContext.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorerContext.cs
new file mode 100644
index 00000000..408968ca
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorerContext.cs
@@ -0,0 +1,79 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.Collections.Immutable;
+using C2CS.Feature.ReadCodeC.Data;
+using C2CS.Foundation;
+using C2CS.Foundation.Diagnostics;
+
+namespace C2CS.Feature.ReadCodeC.Domain.ExploreCode;
+
+public sealed class ClangTranslationUnitExplorerContext
+{
+ public DiagnosticsSink Diagnostics { get; }
+
+ public ImmutableArray IncludeDirectories { get; }
+
+ public ImmutableArray IgnoredFiles { get; }
+
+ public ImmutableArray OpaqueTypesNames { get; }
+
+ public ImmutableArray FunctionNamesWhitelist { get; }
+
+ public TargetPlatform TargetPlatform { get; }
+
+ internal readonly List Enums = new();
+ internal readonly ArrayDeque FrontierGeneral = new();
+ internal readonly ArrayDeque FrontierMacros = new();
+ internal readonly List FunctionPointers = new();
+ internal readonly List Functions = new();
+ internal readonly HashSet MacroFunctionLikeNames = new();
+ internal readonly List MacroObjects = new();
+ internal readonly HashSet Names = new();
+ internal readonly List OpaqueDataTypes = new();
+ internal readonly List Records = new();
+ internal readonly HashSet SystemIgnoredTypeNames = DefaultSystemIgnoredTypeNames();
+ internal readonly List Typedefs = new();
+ internal readonly List Types = new();
+ internal readonly Dictionary TypesByName = new();
+ internal readonly Dictionary ValidTypeNames = new();
+ internal readonly List Variables = new();
+
+ public ClangTranslationUnitExplorerContext(
+ DiagnosticsSink diagnostics,
+ ImmutableArray includeDirectories,
+ ImmutableArray ignoredFiles,
+ ImmutableArray opaqueTypeNames,
+ ImmutableArray functionNamesWhitelist,
+ TargetPlatform targetPlatform)
+ {
+ Diagnostics = diagnostics;
+ IncludeDirectories = includeDirectories;
+ IgnoredFiles = ignoredFiles;
+ OpaqueTypesNames = opaqueTypeNames;
+ FunctionNamesWhitelist = functionNamesWhitelist;
+ TargetPlatform = targetPlatform;
+ }
+
+ private static HashSet DefaultSystemIgnoredTypeNames()
+ {
+ return new HashSet
+ {
+ "FILE",
+ "DIR",
+ "size_t",
+ "ssize_t",
+ "int8_t",
+ "uint8_t",
+ "int16_t",
+ "uint16_t",
+ "int32_t",
+ "uint32_t",
+ "int64_t",
+ "uint64_t",
+ "uintptr_t",
+ "intptr_t",
+ "va_list"
+ };
+ }
+}
diff --git a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Domain/ClangExplorerNode.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorerNode.cs
similarity index 58%
rename from src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Domain/ClangExplorerNode.cs
rename to src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorerNode.cs
index cf7acc19..809c528c 100644
--- a/src/cs/production/C2CS.Feature.ExtractAbstractSyntaxTreeC/Domain/ClangExplorerNode.cs
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/ClangTranslationUnitExplorerNode.cs
@@ -1,29 +1,27 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
-using C2CS.Feature.ExtractAbstractSyntaxTreeC.Data;
+using C2CS.Feature.ReadCodeC.Data;
using static bottlenoselabs.clang;
-namespace C2CS.Feature.ExtractAbstractSyntaxTreeC.Domain;
+namespace C2CS.Feature.ReadCodeC.Domain.ExploreCode;
-public class ClangExplorerNode
+internal sealed class ClangTranslationUnitExplorerNode
{
public readonly CXCursor Cursor;
public readonly CKind Kind;
- public readonly ClangLocation Location;
+ public readonly CLocation Location;
public readonly string? Name;
- public readonly CXType OriginalType;
- public readonly ClangExplorerNode? Parent;
+ public readonly ClangTranslationUnitExplorerNode? Parent;
public readonly CXType Type;
public readonly string? TypeName;
- public ClangExplorerNode(
+ public ClangTranslationUnitExplorerNode(
CKind kind,
- ClangLocation location,
- ClangExplorerNode? parent,
+ CLocation location,
+ ClangTranslationUnitExplorerNode? parent,
CXCursor cursor,
CXType type,
- CXType originalType,
string? name,
string? typeName)
{
@@ -33,15 +31,7 @@ public ClangExplorerNode(
{
if (type.IsPrimitive())
{
- // Primitives don't have a location
- Location = new ClangLocation
- {
- FilePath = string.Empty,
- FileName = "Builtin",
- LineColumn = 0,
- LineNumber = 0,
- IsBuiltin = true
- };
+ Location = CLocation.System;
}
else
{
@@ -56,7 +46,6 @@ public ClangExplorerNode(
Parent = parent;
Cursor = cursor;
Type = type;
- OriginalType = originalType;
Name = name;
TypeName = typeName;
}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/MacroAlreadyExistsDiagnostic.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/MacroAlreadyExistsDiagnostic.cs
new file mode 100644
index 00000000..76e06df8
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/MacroAlreadyExistsDiagnostic.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using C2CS.Foundation.Diagnostics;
+
+namespace C2CS.Feature.ReadCodeC.Domain.ExploreCode.Diagnostics;
+
+public sealed class MacroAlreadyExistsDiagnostic : Diagnostic
+{
+ public MacroAlreadyExistsDiagnostic(string name)
+ : base(DiagnosticSeverity.Warning, CreateMessage(name))
+ {
+ }
+
+ private static string CreateMessage(string name)
+ {
+ return $"A macro with the '{name}' already exists.";
+ }
+}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/PlatformMismatchDiagnostic.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/PlatformMismatchDiagnostic.cs
new file mode 100644
index 00000000..198f8616
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/PlatformMismatchDiagnostic.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using C2CS.Foundation.Diagnostics;
+
+namespace C2CS.Feature.ReadCodeC.Domain.ExploreCode.Diagnostics;
+
+public sealed class PlatformMismatchDiagnostic : Diagnostic
+{
+ public PlatformMismatchDiagnostic(TargetPlatform actualPlatform, TargetPlatform expectedPlatform)
+ : base(DiagnosticSeverity.Error, CreateMessage(actualPlatform, expectedPlatform))
+ {
+ }
+
+ private static string CreateMessage(TargetPlatform actualPlatform, TargetPlatform expectedPlatform)
+ {
+ return $"The C library was expected to have runtime of platform '{expectedPlatform}' but the header file specified a runtime platform of '{actualPlatform}'.";
+ }
+}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/TypeFromIgnoredHeaderDiagnostic.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/TypeFromIgnoredHeaderDiagnostic.cs
new file mode 100644
index 00000000..8e317eab
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Diagnostics/TypeFromIgnoredHeaderDiagnostic.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using C2CS.Foundation.Diagnostics;
+
+namespace C2CS.Feature.ReadCodeC.Domain.ExploreCode.Diagnostics;
+
+public sealed class TypeFromIgnoredHeaderDiagnostic : Diagnostic
+{
+ public TypeFromIgnoredHeaderDiagnostic(string typeName, string headerFilePath)
+ : base(DiagnosticSeverity.Warning, CreateMessage(typeName, headerFilePath))
+ {
+ }
+
+ private static string CreateMessage(string typeName, string headerFilePath)
+ {
+ return $"The type '{typeName}' belongs to the ignored header file '{headerFilePath}', but is used in the abstract syntax tree.";
+ }
+}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Logging.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Logging.cs
new file mode 100644
index 00000000..8822e1c2
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/ExploreCode/Logging.cs
@@ -0,0 +1,143 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using C2CS.Foundation;
+using C2CS.Foundation.Logging;
+using Microsoft.Extensions.Logging;
+
+namespace C2CS.Feature.ReadCodeC.Domain.ExploreCode;
+
+internal static class Logging
+{
+ private static readonly Action ActionExploreCodeFailed =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Failed."),
+ "- Failed");
+
+ private static readonly Action ActionExploreCodeSuccess =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Success"),
+ "- Success");
+
+ private static readonly Action ActionExploreCodeTranslationUnit =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Translation unit"),
+ "- Translation unit {FilePath}");
+
+ private static readonly Action ActionExploreCodeMacro =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Macro"),
+ "- Macro {Name}");
+
+ private static readonly Action ActionExploreCodeVariable =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Variable"),
+ "- Variable {Name}");
+
+ private static readonly Action ActionExploreCodeFunction =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Function"),
+ "- Function {Name}");
+
+ private static readonly Action ActionExploreCodeEnum =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Enum"),
+ "- Enum {Name}");
+
+ private static readonly Action ActionExploreCodeRecord =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Record"),
+ "- Record {Name}");
+
+ private static readonly Action ActionExploreCodeTypedef =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Typedef"),
+ "- Typedef {Name}");
+
+ private static readonly Action ActionExploreCodeOpaqueType =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Opaque type"),
+ "- Opaque type {Name}");
+
+ private static readonly Action ActionExploreCodeFunctionPointer =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Function pointer"),
+ "- Function pointer {Name}");
+
+ private static readonly Action ActionExploreCodeType =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Explore C header file: Type"),
+ "- Type {TypeName}");
+
+ public static void ExploreCodeFailed(this ILogger logger, Exception exception)
+ {
+ ActionExploreCodeFailed(logger, exception);
+ }
+
+ public static void ExploreCodeSuccess(this ILogger logger)
+ {
+ ActionExploreCodeSuccess(logger, null!);
+ }
+
+ public static void ExploreCodeTranslationUnit(this ILogger logger, string filePath)
+ {
+ ActionExploreCodeTranslationUnit(logger, filePath, null!);
+ }
+
+ public static void ExploreCodeMacro(this ILogger logger, string name)
+ {
+ ActionExploreCodeMacro(logger, name, null!);
+ }
+
+ public static void ExploreCodeVariable(this ILogger logger, string name)
+ {
+ ActionExploreCodeVariable(logger, name, null!);
+ }
+
+ public static void ExploreCodeFunction(this ILogger logger, string name)
+ {
+ ActionExploreCodeFunction(logger, name, null!);
+ }
+
+ public static void ExploreCodeEnum(this ILogger logger, string name)
+ {
+ ActionExploreCodeEnum(logger, name, null!);
+ }
+
+ public static void ExploreCodeRecord(this ILogger logger, string name)
+ {
+ ActionExploreCodeRecord(logger, name, null!);
+ }
+
+ public static void ExploreCodeTypedef(this ILogger logger, string name)
+ {
+ ActionExploreCodeTypedef(logger, name, null!);
+ }
+
+ public static void ExploreCodeOpaqueType(this ILogger logger, string name)
+ {
+ ActionExploreCodeOpaqueType(logger, name, null!);
+ }
+
+ public static void ExploreCodeFunctionPointer(this ILogger logger, string name)
+ {
+ ActionExploreCodeFunctionPointer(logger, name, null!);
+ }
+
+ public static void ExploreCodeVisitType(this ILogger logger, string name)
+ {
+ ActionExploreCodeType(logger, name, null!);
+ }
+}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/InstallClang/ClangInstaller.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/InstallClang/ClangInstaller.cs
new file mode 100644
index 00000000..0fb37484
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/InstallClang/ClangInstaller.cs
@@ -0,0 +1,135 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using System.IO.Abstractions;
+using System.IO.Compression;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Microsoft.Extensions.Logging;
+
+namespace C2CS.Feature.ReadCodeC.Domain.InstallClang;
+
+public sealed class ClangInstaller
+{
+ private bool _isInstalled;
+ private readonly object _lock = new();
+
+ private string _clangNativeLibraryFilePath = null!;
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
+
+ public ClangInstaller(ILogger logger, IFileSystem fileSystem)
+ {
+ _logger = logger;
+ _fileSystem = fileSystem;
+ }
+
+ public void Install(NativeOperatingSystem operatingSystem)
+ {
+ lock (_lock)
+ {
+ if (_isInstalled)
+ {
+ _logger.InstallClangSuccessAlreadyInstalled(_clangNativeLibraryFilePath);
+ return;
+ }
+
+ _clangNativeLibraryFilePath = GetClangFilePath(operatingSystem);
+ NativeLibrary.SetDllImportResolver(typeof(bottlenoselabs.clang).Assembly, ResolveClang);
+ _logger.InstallClangSuccess(_clangNativeLibraryFilePath);
+ _isInstalled = true;
+ }
+ }
+
+ private string GetClangFilePath(NativeOperatingSystem operatingSystem)
+ {
+ string result;
+
+ try
+ {
+ result = operatingSystem switch
+ {
+ NativeOperatingSystem.Windows => GetClangFilePathWindows(),
+ NativeOperatingSystem.Linux => GetClangFilePathLinux(),
+ NativeOperatingSystem.macOS => GetClangFilePathMacOs(),
+ _ => string.Empty
+ };
+ }
+ catch (Exception e)
+ {
+ _logger.InstallClangFailed(e);
+ throw;
+ }
+
+ return result;
+ }
+
+ private string GetClangFilePathWindows()
+ {
+ var filePaths = new[]
+ {
+ Path.Combine(AppContext.BaseDirectory, "libclang.dll"),
+ Path.Combine(AppContext.BaseDirectory, "clang.dll"),
+ @"C:\Program Files\LLVM\bin\libclang.dll" // choco install llvm
+ };
+
+ const string errorMessage = "`libclang.dll` or `clang.dll` is missing. Please put a `libclang.dll` or `clang.dll` file next to this application or install Clang for Windows. To install Clang for Windows using Chocolatey, use the command `choco install llvm`.";
+ return SearchForClangFilePath(errorMessage, filePaths);
+ }
+
+ private string GetClangFilePathLinux()
+ {
+ var filePaths = new[]
+ {
+ Path.Combine(AppContext.BaseDirectory, "libclang.so"),
+ "/usr/lib/llvm-10/lib/libclang.so.1" // apt-get install clang
+ };
+
+ const string errorMessage = "`libclang.so`is missing. Please put a `libclang.so` file next to this application or install Clang for Linux. To install Clang for Debian-based linux distributions, use the command `apt-get update && apt-get install clang`.";
+ return SearchForClangFilePath(errorMessage, filePaths);
+ }
+
+ private string GetClangFilePathMacOs()
+ {
+ var filePaths = new[]
+ {
+ Path.Combine(AppContext.BaseDirectory, "libclang.dylib"),
+ "/Library/Developer/CommandLineTools/usr/lib/libclang.dylib" // xcode-select --install
+ };
+
+ const string errorMessage = "`libclang.dylib` is missing. Please put a `libclang.dylib` file next to this application or install CommandLineTools for macOS using the command `xcode-select --install`.";
+ return SearchForClangFilePath(errorMessage, filePaths);
+ }
+
+ private string SearchForClangFilePath(string errorMessage, params string[] filePaths)
+ {
+ var installedFilePath = string.Empty;
+ foreach (var filePath in filePaths)
+ {
+ if (!_fileSystem.File.Exists(filePath))
+ {
+ continue;
+ }
+
+ installedFilePath = filePath;
+ break;
+ }
+
+ if (string.IsNullOrEmpty(installedFilePath))
+ {
+ throw new InvalidOperationException(errorMessage);
+ }
+
+ return installedFilePath;
+ }
+
+ private IntPtr ResolveClang(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
+ {
+ if (!NativeLibrary.TryLoad(_clangNativeLibraryFilePath, out var handle))
+ {
+ throw new ClangException($"Could not load libclang: {_clangNativeLibraryFilePath}");
+ }
+
+ return handle;
+ }
+}
diff --git a/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/InstallClang/Logging.cs b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/InstallClang/Logging.cs
new file mode 100644
index 00000000..e51931f4
--- /dev/null
+++ b/src/cs/production/features/C2CS.Feature.ReadCodeC/Domain/InstallClang/Logging.cs
@@ -0,0 +1,44 @@
+// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.
+
+using C2CS.Foundation;
+using C2CS.Foundation.Logging;
+using Microsoft.Extensions.Logging;
+
+namespace C2CS.Feature.ReadCodeC.Domain.InstallClang;
+
+internal static class Logging
+{
+ private static readonly Action ActionFailed =
+ LoggerMessage.Define(
+ LogLevel.Trace,
+ LoggingEventRegistry.CreateEventIdentifier("Install Clang: Failed."),
+ "- Failed");
+
+ private static readonly Action ActionSuccess =
+ LoggerMessage.Define