99 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			99 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								# 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)
							 |