1#!python 2''' 3Run this script in the mingw64 shell to dynamically compile a list of 4all runtime components of Csound and all their plugins and runtime 5dependencies. System files and some other files are excluded. 6The list is saved as a set of Inno Setup Compiler commands. 7''' 8import fnmatch 9import os 10import os.path 11import shutil 12import subprocess 13 14do_copy = False 15csound_directory = r'D:\msys64\home\restore\csound' 16globs = '*.exe *.dll *.so *.node *.pyd *.py *.pdb *.jar' 17ldd_globs = '*.exe *.dll *.so *.node *.pyd' 18ldd_filepath = r'D:\msys64\usr\bin\ldd' 19 20def exclude(filepath): 21 # Wrong case! 22 if filepath.endswith('CSOUND64.dll'): 23 return True 24 if fnmatch.fnmatch(filepath, '''*/python27.dll'''): 25 return True 26 if fnmatch.fnmatch(filepath, '''*/android/*'''): 27 return True 28 if fnmatch.fnmatch(filepath, '''*/frontends/*'''): 29 return True 30 if fnmatch.fnmatch(filepath, '''*/installer/*'''): 31 return True 32 if fnmatch.fnmatch(filepath, '''*find_csound_dependencies.py'''): 33 return True 34 if fnmatch.fnmatch(filepath, '''*/packages/*.exe'''): 35 return True 36 if fnmatch.fnmatch(filepath, '''*/packages/*.py'''): 37 return True 38 if fnmatch.fnmatch(filepath, '''*/tests/*'''): 39 return True 40 if fnmatch.fnmatch(filepath, '''*/pluginSdk/*'''): 41 return True 42 if fnmatch.fnmatch(filepath, '''*/CMakeFiles/*'''): 43 return True 44 if fnmatch.fnmatch(filepath, '''*/Opcodes/*'''): 45 return True 46 if fnmatch.fnmatch(filepath, '''*/Windows/*'''): 47 return True 48 if fnmatch.fnmatch(filepath, '''*/csound-msvs/*'''): 49 return True 50 if fnmatch.fnmatch(filepath, '''*/msvc/deps/*'''): 51 return True 52 if fnmatch.fnmatch(filepath, '''*/???'''): 53 return True 54 return False 55 56# Generates a line of NSIS code depending upon the type of dependency. 57# All plugin opcodes and loadable modules go in plugins64. 58# All other dependencies go in bin. 59# The logic is: if the file is a DLL or so, if it is not in in the non-opcode 60# list, put the file in plugins64; otherwise, put in bin. 61non_opcode_targets = ''' 62CsoundAC.dll 63CsoundVST.dll 64_CsoundAC.pyd 65_csnd6.pyd 66_jcsound6.dll 67csnd6.dll 68csound64.dll 69luaCsnd6.dll 70luaCsoundAC.dll 71lua51.dll 72csound.node 73'''.split('\n') 74vst_targets = ''' 75CsoundVST.dll 76csoundvstmain.exe 77vst4cs.dll 78'''.split('\n') 79python_targets = ''' 80_csnd6.pyd 81_CsoundAC.pyd 82csnd6.py 83CsoundAC.py 84py.dll 85'''.split('\n') 86module_extensions = '.dll .so .DLL .SO'.split() 87def is_plugin(dependency): 88 path, extension = os.path.splitext(dependency) 89 if extension in module_extensions: 90 if dependency.find('csound-mingw') != -1: 91 path, filename = os.path.split(dependency) 92 if filename not in non_opcode_targets: 93 return True 94 return False 95 96def emit(dependency): 97 if is_plugin(dependency): 98 line = 'Source: "%s"; DestDir: "{#APP_PLUGINS64}"; Flags: ignoreversion; Components: core;\n' % dependency 99 else: 100 line = 'Source: "%s"; DestDir: "{#APP_BIN}"; Flags: ignoreversion; Components: core;\n' % dependency 101 # Patch the command if it is for a VST or Python feature. 102 filename = os.path.split(dependency)[1] 103 if filename in python_targets: 104 line = line.replace('Components: core;', 'Components: python;') 105 if filename in vst_targets: 106 line = line.replace('Components: core;', 'Components: csoundvst;') 107 line = '#ifdef CSOUNDVST\n' + line + '#endif\n' 108 return line 109 110os.chdir(csound_directory) 111targets = set() 112dependencies = set() 113# In order to identify what file some dependency is for. 114with open('mingw64/csound_ldd.txt', 'w') as f: 115 print 'f:', f 116 for dirpath, dirnames, files in os.walk('.'): 117 for glob in globs.split(' '): 118 matches = fnmatch.filter(files, glob) 119 for match in matches: 120 filepath = os.path.join(dirpath, match) 121 print 'filepath:', filepath 122 if (filepath.find('Setup_Csound6_') == -1) and (filepath.find('msvc') == -1): 123 targets.add(filepath) 124 for target in sorted(targets): 125 dependencies.add(target) 126 print 'target:', target 127 for ldd_glob in ldd_globs.split(): 128 if fnmatch.fnmatch(target, ldd_glob): 129 print 'match: ', target 130 popen = subprocess.Popen([ldd_filepath, target], stdout = subprocess.PIPE) 131 output = popen.communicate()[0] 132 print 'output:', output 133 f.write(target + '\n') 134 if len(output) > 1: 135 f.write(output + '\n') 136 for line in output.split('\n'): 137 parts = line.split() 138 if len(parts) > 2: 139 dependencies.add(parts[2]) 140 elif len(parts) > 0: 141 dependencies.add(parts[0]) 142print 143print 'CSOUND TARGETS AND DEPENDENCIES' 144print 145dependencies = sorted(dependencies) 146nonsystem_dependencies = set() 147for dependency in dependencies: 148 realpath = os.path.abspath(dependency) 149 print 'realpath:', realpath 150 # Fix up MSYS pathname confusion. 151 realpath = realpath.replace('\\home\\restore\\', '\\msys64\\home\\restore\\') 152 realpath = realpath.replace('D:\\c\\', 'C:\\') 153 realpath = realpath.replace('D:\\', 'D:\\msys64\\') 154 realpath = realpath.replace('D:\\msys64\\msys64\\', 'D:\\msys64\\') 155 realpath = realpath.replace('D:\\msys64\\msys64\\', 'D:\\msys64\\') 156 print 'fixed :', realpath 157 nonsystem_dependencies.add(realpath) 158nonsystem_dependencies = sorted(nonsystem_dependencies) 159with open('installer/windows/csound_targets_and_dependencies.iss', 'w') as f: 160 for dependency in nonsystem_dependencies: 161 if not exclude(dependency): 162 print 'dependency:', dependency 163 line = emit(dependency) 164 f.write(line) 165