| # Copyright 2022 GlobalFoundries PDK Authors |
| # |
| # 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. |
| """ |
| Script for converting GDS files into SVG files (for easy viewing on GitHub and |
| other tooling). |
| """ |
| |
| import concurrent.futures |
| import os |
| import pathlib |
| import sys |
| |
| import gdstk |
| |
| |
| def conv_to_svg(gds_path): |
| """Convert GDS file into SVG.""" |
| svg_path = gds_path.with_suffix(".svg") |
| |
| if os.path.isfile(svg_path): |
| os.remove(svg_path) |
| |
| library = gdstk.read_gds(gds_path) |
| top_cells = library.top_level() |
| top_cells[0].write_svg(svg_path) |
| |
| |
| def main(args): |
| """Use a processing pool to convert GDS into SVG in parallel.""" |
| if not args: |
| args.insert(".") |
| |
| gdss = [] |
| for arg in args: |
| gdss.extend(pathlib.Path(arg).rglob("*.gds")) |
| gdss.sort() |
| |
| # We can use a with statement to ensure threads are cleaned up promptly |
| failures = [] |
| with concurrent.futures.ProcessPoolExecutor(max_workers=6) as executor: |
| future_to_gds = { |
| executor.submit(conv_to_svg, gds_file): gds_file for gds_file in gdss |
| } |
| for future in concurrent.futures.as_completed(future_to_gds): |
| gds_path = future_to_gds[future] |
| try: |
| print(f"{gds_path} has completed") |
| except Exception as exc: # pylint: disable=broad-except |
| print(f"{gds_path} generated an exception: {exc}") |
| failures.append(gds_path) |
| |
| for gds_path in failures: |
| print(f"ERROR: Unable to convert {gds_path}") |
| |
| # Maximum number of errors that can be returned via exit code is ~100 |
| # (signed char == 128). |
| if len(failures) > 100: |
| return 100 |
| return len(failures) |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main(list(sys.argv[1:]))) |