diff --git a/.clang-format b/.clang-format index 5b2fbe5..c86fa8c 100644 --- a/.clang-format +++ b/.clang-format @@ -1,9 +1,13 @@ # Default Linux style BasedOnStyle: LLVM -IndentWidth: 4 -UseTab: Never +IndentWidth: 8 +UseTab: Always BreakBeforeBraces: Linux AllowShortIfStatementsOnASingleLine: false IndentCaseLabels: false + +# From guidelines/CodingStyle +TabWidth: 8 +ContinuationIndentWidth: 2 ColumnLimit: 150 -AccessModifierOffset: -4 +# BreakBeforeBraces: Linux diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d8b421..a76de52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,21 @@ -name: CI +# Copyright (C) 2025 Mohamed Gaber +# +# Adapted from Yosys wheels +# +# Copyright (C) 2024 Efabless Corporation +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +name: Build Wheels for PyPI # Events that trigger workflow on: @@ -9,79 +26,78 @@ on: jobs: build_wheels: - name: Build Wheels (${{matrix.os.name}}) - runs-on: ${{ matrix.os.runner }} strategy: + fail-fast: false matrix: os: [ { - name: "Ubuntu 20.04", - runner: "ubuntu-20.04", - archs: "x86_64,aarch64", + name: "Ubuntu 22.04", + family: "linux", + runner: "ubuntu-22.04", + archs: "x86_64", + }, + { + name: "Ubuntu 22.04", + family: "linux", + runner: "ubuntu-22.04-arm", + archs: "aarch64", }, - { name: "macOS 11", runner: "macos-11", archs: "x86_64,arm64" }, { - name: "Windows Server 2019", - runner: "windows-2019", + name: "macOS 14", + family: "macos", + runner: "macos-14", + archs: "x86_64,arm64", + }, + { + name: "Windows Server 2022", + runner: "windows-2022", archs: "AMD64,ARM64", }, ] + name: Build Wheels | ${{ matrix.os.name }} | ${{ matrix.os.archs }} + runs-on: ${{ matrix.os.runner }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: true - - if: ${{ matrix.os.runner == 'ubuntu-20.04' }} - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - uses: actions/setup-python@v3 - - name: Install cibuildwheel - run: python -m pip install cibuildwheel==2.15.0 + persist-credentials: false + - uses: actions/setup-python@v5 + - if: ${{ matrix.os.family == 'macos' && matrix.os.archs == 'arm64' }} + name: "[macOS/arm64] Install Python 3.8 (see: https://cibuildwheel.pypa.io/en/stable/faq/#macos-building-cpython-38-wheels-on-arm64)" + uses: actions/setup-python@v5 + with: + python-version: 3.8 - name: Build wheels - run: python -m cibuildwheel --archs ${{ matrix.os.archs }} --output-dir dist - - uses: actions/upload-artifact@v3 + uses: pypa/cibuildwheel@v2.21.1 + env: + CIBW_ARCHS: ${{ matrix.os.archs }} + CIBW_BUILD_VERBOSITY: "1" + CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 + CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 + - uses: actions/upload-artifact@v4 with: - path: ./dist/*.whl - push_to_pypi: - name: Build (and publish, if applicable) - runs-on: ubuntu-20.04 + name: python-wheels-${{ matrix.os.runner }} + path: ./wheelhouse/*.whl + upload_wheels: + name: Upload Wheels + runs-on: ubuntu-latest + # Specifying a GitHub environment is optional, but strongly encouraged + environment: pypi + permissions: + # IMPORTANT: this permission is mandatory for Trusted Publishing + id-token: write needs: build_wheels steps: - - name: Check out Git repository - uses: actions/checkout@v3 + - uses: actions/download-artifact@v4 with: - fetch-depth: 0 - submodules: true - - name: Export Repo URL - run: echo "REPO_URL=https://github.com/${{ github.repository }}" >> $GITHUB_ENV - - name: Export Branch Name - run: echo "BRANCH_NAME=${GITHUB_REF##*/}" >> $GITHUB_ENV - - name: Set Up Python - uses: actions/setup-python@v4 - with: - python-version: "3.6" - - name: Build Distribution - run: | - python3 ./setup.py sdist - - uses: actions/download-artifact@v3 - with: - path: . - - run: mv ./artifact/* ./dist - - name: Set default for env.NEW_TAG - run: echo "NEW_TAG=NO_NEW_TAG" >> $GITHUB_ENV - - name: Check for new version - if: ${{ env.BRANCH_NAME == 'main' }} - run: | - cd ${GITHUB_WORKSPACE}/ && python3 .github/scripts/generate_tag.py - - name: Tag Commit - if: ${{ env.NEW_TAG != 'NO_NEW_TAG' }} - uses: tvdias/github-tagger@v0.0.1 - with: - tag: "${{ env.NEW_TAG }}" - repo-token: "${{ secrets.MY_TOKEN }}" + path: "." + pattern: python-wheels-* + merge-multiple: true + - run: | + ls + mkdir -p ./dist + mv *.whl ./dist - name: Publish - if: ${{ env.NEW_TAG != 'NO_NEW_TAG' }} uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/License b/License new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/License @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MANIFEST.in b/MANIFEST.in index 4bca278..fe6612e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,4 @@ -include Readme.md \ No newline at end of file +include Readme.md +include yosys/kernel/*.h +include yosys/kernel/constids.inc +include yosys/passes/techmap/libparse.* diff --git a/Makefile b/Makefile deleted file mode 100644 index bab4574..0000000 --- a/Makefile +++ /dev/null @@ -1,51 +0,0 @@ - -SRC_DIR = libparse -SWIG_IN = $(SRC_DIR)/libparse.i -SWIG_OUT = $(SRC_DIR)/libparse_wrap.cpp $(SRC_DIR)/libparse.py -SOURCES = $(SRC_DIR)/libparse_wrap.cpp $(SRC_DIR)/py_iostream.cpp $(SRC_DIR)/libparse.cpp -OBJECTS = $(patsubst %.cpp,%.o,$(SOURCES)) -HEADERS = $(SRC_DIR)/libparse.h $(SRC_DIR)/py_iostream.h $(SRC_DIR)/stdio_filebuf.h - -CXXFLAGS += -Wpedantic -g -std=c++11 -I$(shell python3 -c "import sysconfig; print(sysconfig.get_path('include'))") -LDFLAGS += -g -L$(shell python3 -c "import sysconfig; print(sysconfig.get_path('stdlib'))") -EXT = .so - -ifeq ("$(shell uname)", "Darwin") -LDFLAGS += -dynamic -undefined dynamic_lookup -else -LDFLAGS += -shared -endif - -all: _libparse$(EXT) -patch: $(SRC_DIR)/libparse.cpp $(SRC_DIR)/libparse.h -swig_out: $(SWIG_OUT) - -_libparse$(EXT): $(OBJECTS) - $(CXX) $(LDFLAGS) $^ -o $@ - -$(OBJECTS): %.o : %.cpp $(HEADERS) - $(CXX) $(CXXFLAGS) -fPIC -o $@ -c -DFILTERLIB $< - -$(SWIG_OUT): $(SWIG_IN) $(HEADERS) - swig -c++ -o $(SRC_DIR)/libparse_wrap.cpp -oh $(SRC_DIR)/libparse.h -python $< - -$(SRC_DIR)/libparse.h: yosys/passes/techmap/libparse.h $(SRC_DIR)/libparse.h.patch - cp $< $@ - patch $@ $(SRC_DIR)/libparse.h.patch - -$(SRC_DIR)/libparse.cpp: yosys/passes/techmap/libparse.cc $(SRC_DIR)/libparse.cpp.patch - cp $< $@ - patch $@ $(SRC_DIR)/libparse.cpp.patch - -.PHONY: regen-patches -regen-patches: - diff yosys/passes/techmap/libparse.h $(SRC_DIR)/libparse.h > $(SRC_DIR)/libparse.h.patch || true - diff yosys/passes/techmap/libparse.cc $(SRC_DIR)/libparse.cpp > $(SRC_DIR)/libparse.cpp.patch || true - -.PHONY: clean -clean: - rm -f $(SRC_DIR)/libparse*.cpp $(SRC_DIR)/*.o $(SRC_DIR)/libparse.py $(SRC_DIR)/libparse.h - rm -f *.so *.o *.dylib *.dll - rm -rf build/ - rm -rf libparse.egg-info/ - rm -rf dist/ \ No newline at end of file diff --git a/Readme.md b/Readme.md index 580f2ae..d5bd515 100644 --- a/Readme.md +++ b/Readme.md @@ -1,25 +1,38 @@ # libparse-python A SWIG-based Python wrapper around [Yosys](https://github.com/yosyshq/yosys)'s -`libparse`, for all your lib file parsing needs. +`libparse`, for all your dotlib file parsing needs. # Requirements -## Running -* UNIX or UNIX-like operating system (Windows untested) -* Python 3.6+ (CPython or PyPy) with PIP - * `python3 -m pip install wheel` -## Building -Running requirements + +## Running -* A C++11 compiler -* GNU Make -* SWIG +* UNIX or UNIX-like operating system (Windows untested) +* Python 3.8+ (CPython or PyPy) with PIP # License Apache 2.0. Check 'License'. ## Acknowledgements +Original [`libparse-python`]([https://github.com/efabless/libparse-python]) by +Efabless under the Apache 2.0 License. + +``` +Copyright 2024 Efabless Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` + `libparse` from [Yosys](https://github.com/yosyshq/yosys) used under the following conditions: ``` @@ -38,7 +51,7 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ``` -`stdio_filebuf` from [Android Frameworks](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/main/services/vr/performanced) used under the following conditions: +`stdio_filebuf` from [Android Frameworks](https://android.googlesource.com/platform/frameworks/native/+/571ae5f732/services/vr/performanced/stdio_filebuf.h) used under the following conditions: ``` Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT @@ -62,4 +75,4 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` -> The `CREDITS.TXT` in question could not be located. \ No newline at end of file +> The `CREDITS.TXT` in question could not be located. diff --git a/default.nix b/default.nix index 1fd48f4..23dee73 100644 --- a/default.nix +++ b/default.nix @@ -1,46 +1,30 @@ { - python3, - buildPythonPackage, lib, + src ? ./., + buildPythonPackage, pytest, - nix-gitignore, - clang, - swig4, -}: - -let - yosys = builtins.fetchTarball { - url = "https://github.com/yosyshq/yosys/archive/73cb4977b2e493b840b23419919a63be7c83e6df.tar.gz"; - sha256 = "sha256:0rhhx08dia0rd51rp3922vnqzi2fjarz1mrzp27s79k9y5k0mhzk"; - }; -in -buildPythonPackage rec { - name = "libparse"; - + pybind11, +}: let version_file = builtins.readFile ./libparse/__version__.py; version_list = builtins.match ''.+''\n__version__ = "([^"]+)"''\n.+''$'' version_file; version = builtins.head version_list; - - prePatch = '' - rm -rf ./yosys - cp -r ${yosys} ./yosys - ''; +in + buildPythonPackage { + pname = "libparse"; + inherit version; - src = (nix-gitignore.gitignoreSourcePure ./.gitignore ./.); + inherit src; - checkPhase = '' - python3 ./test/test.py - ''; + buildInputs = [ + pybind11 + ]; + + pythonImportsCheck = [ "libparse" ]; - nativeBuildInputs = [ - clang - swig4 - ]; - - meta = with lib; { - description = "Python wrapper around Yosys's libparse"; - license = with licenses; [asl20]; - homepage = "https://github.com/efabless/libpaprse-python"; - platforms = platforms.linux ++ platforms.darwin; - }; -} + meta = with lib; { + description = "Python wrapper around Yosys's libparse"; + license = with licenses; [asl20]; + homepage = "https://github.com/librelane/libparse-python"; + platforms = platforms.linux ++ platforms.darwin; + }; + } diff --git a/flake.lock b/flake.lock index af6d1a7..cdac53d 100644 --- a/flake.lock +++ b/flake.lock @@ -1,23 +1,42 @@ { "nodes": { + "nix-eda": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1756208922, + "narHash": "sha256-6CR+pLQPn3urPdlAmRS4qe2b9IzjyyMB25hy6V68bcc=", + "owner": "fossi-foundation", + "repo": "nix-eda", + "rev": "5fe9ce30351385cead78fe8932210b0683795c80", + "type": "github" + }, + "original": { + "owner": "fossi-foundation", + "repo": "nix-eda", + "type": "github" + } + }, "nixpkgs": { "locked": { - "narHash": "sha256-C36QmoJd5tdQ5R9MC1jM7fBkZW9zBUqbUCsgwS6j4QU=", + "lastModified": 1750400657, + "narHash": "sha256-3vkjFnxCOP6vm5Pm13wC/Zy6/VYgei/I/2DWgW4RFeA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c1be43e8e837b8dbee2b3665a007e761680f0c3d", + "rev": "b2485d56967598da068b5a6946dadda8bfcbcd37", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-23.11", + "ref": "nixos-25.05", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { - "nixpkgs": "nixpkgs" + "nix-eda": "nix-eda" } } }, diff --git a/flake.nix b/flake.nix index dc78f5b..81897b6 100644 --- a/flake.nix +++ b/flake.nix @@ -1,48 +1,45 @@ -# Copyright 2024 Efabless Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. { inputs = { - nixpkgs.url = github:nixos/nixpkgs/nixos-23.11; + self.submodules = true; + nix-eda.url = "github:fossi-foundation/nix-eda"; }; outputs = { self, - nixpkgs, + nix-eda, ... - }: { - # Helper functions - forAllSystems = function: - nixpkgs.lib.genAttrs [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ] ( - system: - function (import nixpkgs { - inherit system; + }: let + nixpkgs = nix-eda.inputs.nixpkgs; + lib = nixpkgs.lib; + in { + overlays = { + default = lib.composeManyExtensions [ + ( + nix-eda.composePythonOverlay (pkgs': pkgs: pypkgs': pypkgs: let + callPythonPackage = lib.callPackageWith (pkgs' // pypkgs'); + in { + libparse = callPythonPackage ./default.nix { + src = self; + }; }) - ); + ) + ]; + }; - # Outputs - packages = self.forAllSystems (pkgs: let - callPackage = pkgs.lib.callPackageWith (pkgs // self.packages.${pkgs.system}); - callPythonPackage = pkgs.lib.callPackageWith (pkgs // pkgs.python3.pkgs // self.packages.${pkgs.system}); - in - rec { - libparse = callPythonPackage ./default.nix {}; - default = libparse; + legacyPackages = nix-eda.forAllSystems ( + system: + import nix-eda.inputs.nixpkgs { + inherit system; + overlays = [nix-eda.overlays.default self.overlays.default]; + } + ); + + packages = nix-eda.forAllSystems ( + system: let + pkgs = self.legacyPackages."${system}"; + in { + inherit (pkgs.python3.pkgs) libparse; + default = self.packages."${system}".libparse; } ); }; diff --git a/libparse/__init__.py b/libparse/__init__.py index f6f5d75..7006b90 100644 --- a/libparse/__init__.py +++ b/libparse/__init__.py @@ -1,2 +1,2 @@ -from .libparse import * +from _libparse import * from .__version__ import __version__ diff --git a/libparse/__version__.py b/libparse/__version__.py index aac5049..e6923f0 100644 --- a/libparse/__version__.py +++ b/libparse/__version__.py @@ -1,3 +1,8 @@ + +# Copyright 2025 Mohamed Gaber +# +# Adapted from libparse-python +# # Copyright 2024 Efabless Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -11,7 +16,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.3.1" +__version__ = "1.0.0" if __name__ == "__main__": print(__version__, end="") diff --git a/libparse/libparse.cpp.patch b/libparse/libparse.cpp.patch deleted file mode 100644 index 47d3023..0000000 --- a/libparse/libparse.cpp.patch +++ /dev/null @@ -1,45 +0,0 @@ -40,41d39 -< for (auto child : children) -< delete child; -45c43 -< LibertyAst *LibertyAst::find(std::string name) ---- -> std::shared_ptr LibertyAst::find(std::string name) -185c183 -< LibertyAst *LibertyParser::parse() ---- -> std::shared_ptr LibertyParser::parse() -225c223 -< LibertyAst *ast = new LibertyAst; ---- -> auto ast = std::make_shared(); -340c338 -< LibertyAst *child = parse(); ---- -> auto child = parse(); -409c407 -< LibertyAst *find_non_null(LibertyAst *node, const char *name) ---- -> std::shared_ptr find_non_null(std::shared_ptr node, const char *name) -411c409 -< LibertyAst *ret = node->find(name); ---- -> auto ret = node->find(name); -458c456 -< void event2vl(LibertyAst *ast, std::string &edge, std::string &expr) ---- -> void event2vl(std::shared_ptr ast, std::string &edge, std::string &expr) -492c490 -< void gen_verilogsim_cell(LibertyAst *ast) ---- -> void gen_verilogsim_cell(std::shared_ptr ast) -525,526c523,524 -< LibertyAst *dir = find_non_null(child, "direction"); -< LibertyAst *func = child->find("function"); ---- -> auto dir = find_non_null(child, "direction"); -> auto func = child->find("function"); -652c650 -< void gen_verilogsim(LibertyAst *ast) ---- -> void gen_verilogsim(std::shared_ptr ast) diff --git a/libparse/libparse.h.patch b/libparse/libparse.h.patch deleted file mode 100644 index e799532..0000000 --- a/libparse/libparse.h.patch +++ /dev/null @@ -1,40 +0,0 @@ -1a2,20 -> Modifications performed by Efabless Corporation to use automatic memory -> management. License follows: -> -> Copyright (C) 2023 Efabless Corporation -> -> Licensed under the Apache License, Version 2.0 (the "License"); -> you may not use this file except in compliance with the License. -> You may obtain a copy of the License at -> -> http://www.apache.org/licenses/LICENSE-2.0 -> -> Unless required by applicable law or agreed to in writing, software -> distributed under the License is distributed on an "AS IS" BASIS, -> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -> See the License for the specific language governing permissions and -> limitations under the License. -> */ -> -> /* -26a46 -> #include -34c54 -< std::vector children; ---- -> std::vector> children; -36c56 -< LibertyAst *find(std::string name); ---- -> std::shared_ptr find(std::string name); -46c66 -< LibertyAst *ast; ---- -> std::shared_ptr ast; -48d67 -< ~LibertyParser() { if (ast) delete ast; } -57c76 -< LibertyAst *parse(); ---- -> std::shared_ptr parse(); diff --git a/libparse/libparse.i b/libparse/libparse.i deleted file mode 100644 index ae93ac5..0000000 --- a/libparse/libparse.i +++ /dev/null @@ -1,35 +0,0 @@ -/* File: libparse.i */ -%module(package="libparse", moduleimport="import _libparse") libparse -%include -%include -%include - -%{ -#define SWIG_FILE_WITH_INIT -#define Py_LIMITED_API 0x030600F0 -#include -#include -#include "libparse.h" -#include "py_iostream.h" -%} - - -%shared_ptr(Yosys::LibertyAst) -%immutable Yosys::LibertyParser::f; -%template(VectorLibertyAstSP) std::vector< std::shared_ptr >; -%template(VectorStr) std::vector< std::string >; - -%typemap(in) std::istream& { - try { - $1 = PyIStream::make_from($input); - } catch (std::runtime_error &e) { - std::cerr << e.what() << std::endl; - SWIG_exception(SWIG_TypeError, e.what()); - } -} - -%typemap(freearg) std::istream& { - delete $1; -} - -%include "libparse.h" diff --git a/libparse/py_iostream.cpp b/libparse/py_iostream.cpp deleted file mode 100644 index 7378a60..0000000 --- a/libparse/py_iostream.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "py_iostream.h" - -PyIStream *PyIStream::make_from(PyObject *pyfile) -{ - if (pyfile == Py_None) { - throw std::runtime_error("None is not a valid input stream"); - } - auto fileno = PyObject_GetAttrString(pyfile, "fileno"); - if (!fileno) { // NOT NONE!! NULL!! - throw std::runtime_error("Passed object has no fileno() method"); - } - - auto fd = PyObject_AsFileDescriptor(pyfile); - if (fd == -1) { - throw std::runtime_error("Failed to get file descriptor"); - } - - auto f = fdopen(fd, "r"); - if (!f) { - throw std::runtime_error("Failed to open input stream"); - } - - return new PyIStream(new stdio_filebuf(f)); -} \ No newline at end of file diff --git a/libparse/py_iostream.h b/libparse/py_iostream.h deleted file mode 100644 index eb947a8..0000000 --- a/libparse/py_iostream.h +++ /dev/null @@ -1,19 +0,0 @@ -#define Py_LIMITED_API 0x030600F0 -#include "Python.h" -#include "stdio_filebuf.h" - -struct PyIStream : public std::istream { - PyIStream(stdio_filebuf *buffer) : std::istream(buffer), buffer(buffer) {} - - static PyIStream *make_from(PyObject *pyfile); - - ~PyIStream() - { - if (buffer) { - delete buffer; - } - } - -private: - stdio_filebuf *buffer = nullptr; -}; \ No newline at end of file diff --git a/libparse/stdio_filebuf.h b/libparse/stdio_filebuf.h index c12b35b..0a9fddd 100644 --- a/libparse/stdio_filebuf.h +++ b/libparse/stdio_filebuf.h @@ -1,8 +1,27 @@ +// Copyright 2025 Mohamed Gaber +// +// Adapted from libparse-python +// +// Copyright 2024 Efabless Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include #include #include -// https://android.googlesource.com/platform/frameworks/native/+/refs/heads/main/services/vr/performanced +// From https://android.googlesource.com/platform/frameworks/native/+/571ae5f732/services/vr/performanced/stdio_filebuf.h +// // Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT // Copyright (c) 2016 Google, Inc. // @@ -167,4 +186,4 @@ template typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_ __last_consumed_ = __c; __last_consumed_is_next_ = true; return __c; -} \ No newline at end of file +} diff --git a/libparse/wrapper.cpp b/libparse/wrapper.cpp new file mode 100644 index 0000000..fcc2a47 --- /dev/null +++ b/libparse/wrapper.cpp @@ -0,0 +1,72 @@ +// Copyright 2025 Mohamed Gaber +// +// Partially adapted from libparse-python +// +// Copyright 2024 Efabless Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "libparse.h" +#include "stdio_filebuf.h" + +namespace py = pybind11; +using namespace Yosys; + +struct PyIStream : public std::istream { + PyIStream(FILE *f) : std::istream(&buffer_), buffer_(f) {} + + static PyIStream *make_from(const py::object &pyfile) + { + if (pyfile.is(py::none())) { + throw std::runtime_error("None is not a valid input stream"); + } + + auto fd_attr = pyfile.attr("fileno"); + auto fd = fd_attr.cast(); + if (fd == -1) { + throw std::runtime_error("Failed to get file descriptor"); + } + + auto f = fdopen(fd, "r"); + if (!f) { + throw std::runtime_error("Failed to open input stream"); + } + + return new PyIStream(f); + } + + private: + stdio_filebuf buffer_; +}; + +LibertyParser *from_file(const py::object &pyfile) +{ + auto cxx_stream = PyIStream::make_from(pyfile); + return new LibertyParser(*cxx_stream); +} + +PYBIND11_MODULE(_libparse, m) +{ + m.doc() = "libparse from yosys, native component"; + py::class_(m, "LibertyAst") + .def(py::init()) + .def_readonly("id", &LibertyAst::id) + .def_readonly("value", &LibertyAst::value) + .def_readonly("args", &LibertyAst::args) + .def_readonly("children", &LibertyAst::children) + .def("find", &LibertyAst::find); + py::class_(m, "LibertyParser").def(py::init(&from_file)).def_readonly("ast", &LibertyParser::ast); +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..233c8fb --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = [ + "setuptools>=42", + "pybind11>=2.10.0", +] +build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index d05f57e..f014c63 100644 --- a/setup.py +++ b/setup.py @@ -1,72 +1,37 @@ #!/usr/bin/env python3 -import os import sys -import platform import subprocess -from setuptools import setup, Extension -from setuptools.command.build_py import build_py as _build_py +from pathlib import Path +from setuptools import setup +from pybind11.setup_helpers import Pybind11Extension, build_ext -module_name = "libparse" -__dir__ = os.path.dirname(os.path.abspath(__file__)) - -version = subprocess.check_output( - [ - sys.executable, - os.path.join( - os.path.abspath(__dir__), - module_name, - "__version__.py", - ), - ], +__file_dir__ = Path(__file__).absolute().parent +__version__ = subprocess.check_output( + [sys.executable, __file_dir__ / "libparse" / "__version__.py"], encoding="utf8", -) - -compiler_opts = ["-std=c++11", "-DFILTERLIB"] -if platform.system() == "Windows": - compiler_opts = ["/DFILTERLIB"] +).strip() -ext = Extension( - name="_libparse", - swig_opts=["-c++"], - sources=[ - "libparse/libparse.cpp", - "libparse/py_iostream.cpp", - "libparse/libparse.i", - ], - include_dirs=[ - "libparse", +ext = Pybind11Extension( + "_libparse", + [ + "libparse/wrapper.cpp", + "yosys/passes/techmap/libparse.cc", ], - extra_compile_args=compiler_opts, + include_dirs=["yosys/passes/techmap", "yosys"], + define_macros=[("FILTERLIB", "1"), ("_YOSYS_", "1")], ) - -class build_py(_build_py): - def run(self) -> None: - subprocess.check_call(["make", "patch"], cwd=__dir__) - self.run_command("build_ext") - return super().run() - - setup( - name=module_name, + name="lln-libparse", packages=["libparse"], - version=version, + version=__version__, description="Python wrapper around Yosys' libparse module", - long_description=open(os.path.join(__dir__, "Readme.md")).read(), + long_description=open(__file_dir__ / "Readme.md").read(), long_description_content_type="text/markdown", - author="Efabless Corporation and Contributors", - author_email="donn@efabless.com", + author="Mohamed Gaber", + author_email="me@donn.website", install_requires=["wheel"], - classifiers=[ - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3", - "Intended Audience :: Developers", - "Operating System :: POSIX :: Linux", - "Operating System :: MacOS :: MacOS X", - ], - python_requires=">3.6", + python_requires=">3.8", ext_modules=[ext], - cmdclass={ - "build_py": build_py, - }, + cmdclass={"build_ext": build_ext}, ) diff --git a/test/test.lib b/test/test.lib deleted file mode 100644 index d95b053..0000000 --- a/test/test.lib +++ /dev/null @@ -1,39 +0,0 @@ -library ("sky130_fd_sc_hd__tt_025C_1v80") { - define(def_sim_opt,library,string); - define(default_arc_mode,library,string); - define(default_constraint_arc_mode,library,string); - define(driver_model,library,string); - define(leakage_sim_opt,library,string); - define(min_pulse_width_mode,library,string); - define(simulator,library,string); - define(switching_power_split_model,library,string); - define(sim_opt,timing,string); - define(violation_delay_degrade_pct,timing,string); - technology("cmos"); - delay_model : "table_lookup"; - bus_naming_style : "%s[%d]"; - time_unit : "1ns"; - voltage_unit : "1V"; - leakage_power_unit : "1nW"; - current_unit : "1mA"; - pulling_resistance_unit : "1kohm"; - capacitive_load_unit(1.0000000000, "pf"); - revision : 1.0000000000; - default_cell_leakage_power : 0.0000000000; - default_fanout_load : 1.0000000000; - default_inout_pin_cap : 0.0000000000; - default_input_pin_cap : 0.0000000000; - default_max_transition : 1.5000000000; - default_output_pin_cap : 0.0000000000; - default_arc_mode : "worst_edges"; - default_constraint_arc_mode : "worst"; - default_leakage_power_density : 0.0000000000; - default_operating_conditions : "tt_025C_1v80"; - operating_conditions ("tt_025C_1v80") { - voltage : 1.8000000000; - process : 1.0000000000; - temperature : 25.000000000; - tree_type : "balanced_tree"; - } - /* Wire load tables */ -} \ No newline at end of file diff --git a/test/test.py b/test/test.py deleted file mode 100644 index e0bc714..0000000 --- a/test/test.py +++ /dev/null @@ -1,28 +0,0 @@ -import os -import sys - -__dir__ = os.path.dirname(__file__) -sys.path.insert(0, os.path.dirname(__dir__)) - -import libparse - -in_file = open(os.path.join(__dir__, "test.lib")) - -x = libparse.LibertyParser(in_file) -ast = x.ast -default_operating_conditions = None -operating_conditions_raw = {} -for child in ast.children: - if child.id == "default_operating_conditions": - default_operating_conditions = child - if child.id == "operating_conditions": - operating_conditions_raw[child.args[0]] = child - - -if default_operating_conditions is None: - if len(operating_conditions_raw) != 1: - print("nooo!!!!") - exit(-1) - default_operating_conditions = operating_conditions_raw.values()[0] - -print(default_operating_conditions.id, default_operating_conditions.value)