cs.py (6397B)
1 #!/usr/bin/env python 2 # encoding: utf-8 3 # Thomas Nagy, 2006-2018 (ita) 4 5 """ 6 C# support. A simple example:: 7 8 def configure(conf): 9 conf.load('cs') 10 def build(bld): 11 bld(features='cs', source='main.cs', gen='foo') 12 13 Note that the configuration may compile C# snippets:: 14 15 FRAG = ''' 16 namespace Moo { 17 public class Test { public static int Main(string[] args) { return 0; } } 18 }''' 19 def configure(conf): 20 conf.check(features='cs', fragment=FRAG, compile_filename='test.cs', gen='test.exe', 21 bintype='exe', csflags=['-pkg:gtk-sharp-2.0'], msg='Checking for Gtksharp support') 22 """ 23 24 from waflib import Utils, Task, Options, Errors 25 from waflib.TaskGen import before_method, after_method, feature 26 from waflib.Tools import ccroot 27 from waflib.Configure import conf 28 29 ccroot.USELIB_VARS['cs'] = set(['CSFLAGS', 'ASSEMBLIES', 'RESOURCES']) 30 ccroot.lib_patterns['csshlib'] = ['%s'] 31 32 @feature('cs') 33 @before_method('process_source') 34 def apply_cs(self): 35 """ 36 Create a C# task bound to the attribute *cs_task*. There can be only one C# task by task generator. 37 """ 38 cs_nodes = [] 39 no_nodes = [] 40 for x in self.to_nodes(self.source): 41 if x.name.endswith('.cs'): 42 cs_nodes.append(x) 43 else: 44 no_nodes.append(x) 45 self.source = no_nodes 46 47 bintype = getattr(self, 'bintype', self.gen.endswith('.dll') and 'library' or 'exe') 48 self.cs_task = tsk = self.create_task('mcs', cs_nodes, self.path.find_or_declare(self.gen)) 49 tsk.env.CSTYPE = '/target:%s' % bintype 50 tsk.env.OUT = '/out:%s' % tsk.outputs[0].abspath() 51 self.env.append_value('CSFLAGS', '/platform:%s' % getattr(self, 'platform', 'anycpu')) 52 53 inst_to = getattr(self, 'install_path', bintype=='exe' and '${BINDIR}' or '${LIBDIR}') 54 if inst_to: 55 # note: we are making a copy, so the files added to cs_task.outputs won't be installed automatically 56 mod = getattr(self, 'chmod', bintype=='exe' and Utils.O755 or Utils.O644) 57 self.install_task = self.add_install_files(install_to=inst_to, install_from=self.cs_task.outputs[:], chmod=mod) 58 59 @feature('cs') 60 @after_method('apply_cs') 61 def use_cs(self): 62 """ 63 C# applications honor the **use** keyword:: 64 65 def build(bld): 66 bld(features='cs', source='My.cs', bintype='library', gen='my.dll', name='mylib') 67 bld(features='cs', source='Hi.cs', includes='.', bintype='exe', gen='hi.exe', use='mylib', name='hi') 68 """ 69 names = self.to_list(getattr(self, 'use', [])) 70 get = self.bld.get_tgen_by_name 71 for x in names: 72 try: 73 y = get(x) 74 except Errors.WafError: 75 self.env.append_value('CSFLAGS', '/reference:%s' % x) 76 continue 77 y.post() 78 79 tsk = getattr(y, 'cs_task', None) or getattr(y, 'link_task', None) 80 if not tsk: 81 self.bld.fatal('cs task has no link task for use %r' % self) 82 self.cs_task.dep_nodes.extend(tsk.outputs) # dependency 83 self.cs_task.set_run_after(tsk) # order (redundant, the order is inferred from the nodes inputs/outputs) 84 self.env.append_value('CSFLAGS', '/reference:%s' % tsk.outputs[0].abspath()) 85 86 @feature('cs') 87 @after_method('apply_cs', 'use_cs') 88 def debug_cs(self): 89 """ 90 The C# targets may create .mdb or .pdb files:: 91 92 def build(bld): 93 bld(features='cs', source='My.cs', bintype='library', gen='my.dll', csdebug='full') 94 # csdebug is a value in (True, 'full', 'pdbonly') 95 """ 96 csdebug = getattr(self, 'csdebug', self.env.CSDEBUG) 97 if not csdebug: 98 return 99 100 node = self.cs_task.outputs[0] 101 if self.env.CS_NAME == 'mono': 102 out = node.parent.find_or_declare(node.name + '.mdb') 103 else: 104 out = node.change_ext('.pdb') 105 self.cs_task.outputs.append(out) 106 107 if getattr(self, 'install_task', None): 108 self.pdb_install_task = self.add_install_files( 109 install_to=self.install_task.install_to, install_from=out) 110 111 if csdebug == 'pdbonly': 112 val = ['/debug+', '/debug:pdbonly'] 113 elif csdebug == 'full': 114 val = ['/debug+', '/debug:full'] 115 else: 116 val = ['/debug-'] 117 self.env.append_value('CSFLAGS', val) 118 119 @feature('cs') 120 @after_method('debug_cs') 121 def doc_cs(self): 122 """ 123 The C# targets may create .xml documentation files:: 124 125 def build(bld): 126 bld(features='cs', source='My.cs', bintype='library', gen='my.dll', csdoc=True) 127 # csdoc is a boolean value 128 """ 129 csdoc = getattr(self, 'csdoc', self.env.CSDOC) 130 if not csdoc: 131 return 132 133 node = self.cs_task.outputs[0] 134 out = node.change_ext('.xml') 135 self.cs_task.outputs.append(out) 136 137 if getattr(self, 'install_task', None): 138 self.doc_install_task = self.add_install_files( 139 install_to=self.install_task.install_to, install_from=out) 140 141 self.env.append_value('CSFLAGS', '/doc:%s' % out.abspath()) 142 143 class mcs(Task.Task): 144 """ 145 Compile C# files 146 """ 147 color = 'YELLOW' 148 run_str = '${MCS} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}' 149 150 def split_argfile(self, cmd): 151 inline = [cmd[0]] 152 infile = [] 153 for x in cmd[1:]: 154 # csc doesn't want /noconfig in @file 155 if x.lower() == '/noconfig': 156 inline.append(x) 157 else: 158 infile.append(self.quote_flag(x)) 159 return (inline, infile) 160 161 def configure(conf): 162 """ 163 Find a C# compiler, set the variable MCS for the compiler and CS_NAME (mono or csc) 164 """ 165 csc = getattr(Options.options, 'cscbinary', None) 166 if csc: 167 conf.env.MCS = csc 168 conf.find_program(['csc', 'mcs', 'gmcs'], var='MCS') 169 conf.env.ASS_ST = '/r:%s' 170 conf.env.RES_ST = '/resource:%s' 171 172 conf.env.CS_NAME = 'csc' 173 if str(conf.env.MCS).lower().find('mcs') > -1: 174 conf.env.CS_NAME = 'mono' 175 176 def options(opt): 177 """ 178 Add a command-line option for the configuration:: 179 180 $ waf configure --with-csc-binary=/foo/bar/mcs 181 """ 182 opt.add_option('--with-csc-binary', type='string', dest='cscbinary') 183 184 class fake_csshlib(Task.Task): 185 """ 186 Task used for reading a foreign .net assembly and adding the dependency on it 187 """ 188 color = 'YELLOW' 189 inst_to = None 190 191 def runnable_status(self): 192 return Task.SKIP_ME 193 194 @conf 195 def read_csshlib(self, name, paths=[]): 196 """ 197 Read a foreign .net assembly for the *use* system:: 198 199 def build(bld): 200 bld.read_csshlib('ManagedLibrary.dll', paths=[bld.env.mylibrarypath]) 201 bld(features='cs', source='Hi.cs', bintype='exe', gen='hi.exe', use='ManagedLibrary.dll') 202 203 :param name: Name of the library 204 :type name: string 205 :param paths: Folders in which the library may be found 206 :type paths: list of string 207 :return: A task generator having the feature *fake_lib* which will call :py:func:`waflib.Tools.ccroot.process_lib` 208 :rtype: :py:class:`waflib.TaskGen.task_gen` 209 """ 210 return self(name=name, features='fake_lib', lib_paths=paths, lib_type='csshlib') 211