| # PortAudio Repository .def file checker |
| # |
| # Run this script from the root of the repository using the command: |
| # python pa_compare_def_files.py |
| # |
| # The PortAudio repository contains two (semi-redundant) .def |
| # files that specify exported symbols for Windows dynamic link libraries. |
| # |
| # This script checks that the two .def files export the same symbols |
| # using the same ordinals. |
| # |
| # The .def files are: |
| # |
| # 1. msvc/portaudio.def |
| # 2. cmake/portaudio.def.in |
| # |
| # The CMake .def.in file is an input that generates a .def file |
| # with host-api-specific symbols commented out when a particular host API |
| # is not built. |
| |
| import sys |
| |
| msvc_portaudio_def_path = "msvc/portaudio.def" |
| cmake_portaudio_def_in_path = "cmake/portaudio.def.in" |
| |
| def parse_def_file(file): |
| result = {} |
| for line in file: |
| line = line.strip() |
| if line: |
| if "EXPORTS" in line or line[0] == ";": |
| continue |
| columns = line.split() |
| #print(columns) |
| symbol, ordinal = columns |
| #print(symbol, ordinal) |
| if ordinal in result: |
| print(f"error: ordinal {ordinal} referenced multiple times") |
| result[ordinal] = symbol |
| return result |
| |
| with open(msvc_portaudio_def_path, mode="rt", encoding="utf-8") as msvc_portaudio_def: |
| msvc_portaudio_def_syms = parse_def_file(msvc_portaudio_def) |
| |
| with open(cmake_portaudio_def_in_path, mode="rt", encoding="utf-8") as cmake_portaudio_def_in: |
| cmake_portaudio_def_in_syms = parse_def_file(cmake_portaudio_def_in) |
| |
| def clear_cmake_exclude_condition_prefix(sym): |
| if "@" in sym: |
| return sym.split("@")[-1] |
| else: |
| return sym |
| |
| # dictionary keys are the ordinals |
| ordinals = list(set(msvc_portaudio_def_syms.keys()).union(cmake_portaudio_def_in_syms.keys())) |
| ordinals.sort(key=lambda s: int(s.replace("@", ""))) |
| |
| msvcMissingCount = 0 |
| cmakeMissingCount = 0 |
| differenceCount = 0 |
| |
| print("ordinal, msvc, cmake, remark") |
| for ordinal in ordinals: |
| msvc_sym = msvc_portaudio_def_syms[ordinal] if ordinal in msvc_portaudio_def_syms else "" |
| cmake_sym = cmake_portaudio_def_in_syms[ordinal] if ordinal in cmake_portaudio_def_in_syms else "" |
| |
| cmake_sym_no_cond = clear_cmake_exclude_condition_prefix(cmake_sym) |
| |
| remark = "" |
| if not msvc_sym: |
| remark = "missing in msvc/portaudio.def" |
| msvcMissingCount += msvcMissingCount |
| elif not cmake_sym: |
| remark = "missing in cmake/portaudio.def.in" |
| cmakeMissingCount += cmakeMissingCount |
| elif msvc_sym != cmake_sym_no_cond: |
| remark = "differs" |
| differenceCount += 1 |
| else: |
| remark = "ok" |
| |
| print(f"{ordinal}, {msvc_sym}, {cmake_sym}, {remark}") |
| |
| print("SUMMARY") |
| print("=======") |
| issuesFound = msvcMissingCount > 0 or cmakeMissingCount > 0 or differenceCount > 0 |
| if msvcMissingCount > 0: |
| print(f"error: {msvc_portaudio_def_path} ({msvcMissingCount} missing symbols)") |
| if cmakeMissingCount > 0: |
| print(f"error: {cmake_portaudio_def_in_path} ({cmakeMissingCount} missing symbols)") |
| if differenceCount > 0: |
| print(f"error: there are {differenceCount} ordinals with non-matching symbols") |
| |
| if issuesFound: |
| sys.exit(1) |
| else: |
| print("No issues found. All good.") |
| sys.exit(0) |