srt_ntide_target.py
Go to the documentation of this file.
1 #
2 # ide_target.py
3 #
4 # An object that keeps track of a single target the IDE has to build... This includes
5 # things like object files, by the way. So not all targets translate to projects in the
6 # ide (the routine is_a_project determines which targets are projects and which are not).
7 #
8 # This is the place to mess around if you need to change things like what targets are built,
9 # or what the targets are named in the ide, etc.
10 #
11 # Created November 1997 Gordon Watts (1997)
12 #
13 
14 import string
15 import os
16 import regex
17 import regsub
18 
19 import srt_path_util
20 
21 # The file types definition -- so we can figure out what we are dealing with
22 # File type classes for source files -- there are only a few
23 source_file_classes = {}
24 source_file_classes["cpp"] = ["cpp", "c", "cc", "cxx"]
25 source_file_classes["f"] = ["f", "f77", "f90", "F"]
26 
27 # Executable files
28 exe_file_types = ["exe", "x", "", "tst"]
29 
30 # Header files
31 header_file_types = ["hpp", "h"]
32 
33 
34 ####
35 # A list of all the source file types -- built from above.
36 source_file_types = []
37 for source_class in source_file_classes.keys():
38  for source_type in source_file_classes[source_class]:
39  source_file_types.append(source_type)
40 
41 class ide_target:
42 
43  def __init__ (self, ide_file_handle = "", newrel_dir = ""):
44  self._option_list = []
46  self._include_paths = []
48  self._source_files = [] # Can contain only source_file_types
49  self._header_files = []
51  self._lib_files_to_add = [] # Contains all other types.
52  self._newrel_directory = newrel_dir
53  self._bfarch = os.environ["BFARCH"]
55  self._working_dir = ""
56  self._package_name = ""
57  self._link_options = []
58 
59  self.reset_target_files ()
60  self.reset_libraries ()
61 
62  if ide_file_handle != "":
63  self.parse_from_file (ide_file_handle)
64 
65 
66  #
67  # reset_target_files
68  #
69  # Clear out all the possible destination files
70  #
71  def reset_target_files (self):
72  self._build_file = ""
73  self._library_file = ""
74  self._exe_name = ""
75 
76  #
77  # reset_libraries
78  #
79  # Reset all the library stuff
80  #
81  def reset_libraries (self):
84 
85  #
86  # parse_from_file
87  #
88  # Read everything in from a file
89  #
90  def parse_from_file (self, ide_file_handle):
91 
92  star_line = ide_file_handle.get_line()
93 
94  ide_file_handle.load_buffer()
95  while ide_file_handle.there_is_more() and (not ide_file_handle.is_star_line()):
96  line = ide_file_handle.get_line()
97 
98  line_word_list = string.split (line, " ", 1)
99  command = line_word_list[0]
100  option = ""
101  if len(line_word_list) == 2:
102  option = line_word_list[1]
103 
104  if command == "option":
105  self._option_list.append(option)
106  elif command == "link_option":
107  self._link_options.append(option)
108  elif command == "define_macro":
109  self._macro_definitions.append(option)
110  elif command == "include_file_path":
111  if (option != ".") and (option != ""):
112  self._include_paths.append(option)
113  elif command == "unix_include_file_path":
114  if (option != ".") and (option != ""):
115  self._unix_include_paths.append(option)
116  elif command == "do_compile_only":
117  self._option_list.append("c")
118  elif command == "h_filename":
119  self._header_files.append(option)
120  elif command == "source_file":
121  self.add_source_file (option)
122  elif command == "source_file_cpp":
123  self.add_source_file (option)
124  self._forced_cpp_files[option] = "cpp"
125  elif command == "special_command":
126  self._special_commands.append(option)
127  elif command == "add_and_create":
128  i = 10
129  elif command == "build_obj":
130  if self._build_file != "":
131  raise "Cannot build more than one output file per target!"
132  self._build_file = option
133  elif command == "build_file":
134  if self._build_file != "":
135  raise "Cannot build more than one output file per target!"
136  self._build_file = option
137  elif command == "library_file":
138  if self._library_file != "":
139  raise "Cannot build more than one library file per target!"
140  self._library_file = option
141  elif command == "library":
142  self._link_library_files.append (option)
143  elif command == "add_file":
144  self._lib_files_to_add.append (option)
145  elif command == "library_search_path":
146  self._library_search_paths.append (option)
147  elif command == "build_app":
148  if self._exe_name != "":
149  raise "Cannot build more than one exe per target!"
150  self._exe_name = option
151  elif command == "working_dir":
152  common_prefix = os.path.commonprefix ([option, self._newrel_directory])
153  if common_prefix != self._newrel_directory:
154  raise "Working directory must be subdir of newrelease directory!"
155  self._working_dir = option[len(self._newrel_directory)+1:]
156  elif command == "package_name":
157  self._package_name = option
158  else:
159  print "Unknown IDE Make file option: " + command
160  raise "Could not parse the file"
161 
162  ide_file_handle.load_buffer()
163 
164  target_count = 0
165  if self._build_file != "":
166  target_count = target_count + 1
167  if self._library_file != "":
168  target_count = target_count + 1
169  if self._exe_name != "":
170  target_count = target_count + 1
171 
172  if target_count == 0:
173  raise "No targets found for file!"
174  if target_count > 1:
175  raise "Too many targets found for file!"
176 
177  #
178  # set_compile_only
179  #
180  # Set if we are only building an object or linking as well. This has
181  # a big-time bug in it...
182  #
183  def set_compile_only (self, do_it):
184  if do_it:
185  if "c" not in self._option_list:
186  self._option_list.append ("c")
187  else:
188  raise "Don't know how to remove the C option yet!"
189 
190  #
191  # get_target_name
192  #
193  # Return the name of the target for this file. This is a fully qualified name,
194  # including path info (potentially).
195  #
196  def get_target_name (self):
197  if (self._library_file != "") and (self._build_file != ""):
198  raise "Both library and build are non-zero!"
199  if self._build_file != "":
200  return self._build_file
201  if self._library_file != "":
202  return self._library_file
203  if self._exe_name != "":
204  return self._exe_name
205 
206  raise "Should never get here!"
207 
208  #
209  # set_build_obj
210  #
211  # Set the build object
212  #
213  def set_build_obj (self, filename):
214  self._build_file = filename
215 
216  #
217  # get_target_type
218  #
219  # Return the extension that has the target type in it. NOTE: we assume that if
220  # there is no filetype here, we are dealing with a .exe... this may not be a good
221  # thing!
222  #
223  def get_target_type (self):
224  fname = self.get_target_name_root()
225  pos = regex.search ("\.[^\.]*$", fname)
226  if pos == -1:
227  t_type = "exe"
228  else:
229  t_type = fname[pos+1:]
230 
231  if t_type in exe_file_types:
232  return "exe"
233  return t_type
234 
235 
236  #
237  # get_target_name_root
238  #
239  # Return the name of this target (no path allowed)
240  #
242  return os.path.basename (self.get_target_name())
243 
245  (name, exten) = os.path.splitext (self.get_target_name_root())
246  return name
247 
248  #
249  # combine
250  #
251  # There is another ide_target object with the same target name as we have. Attempt
252  # to combine these two guys.
253  #
254  # Really should check to make sure other stuff is correct, but not for now!
255  #
256  def combine (self, other_target):
257 
258  if self.get_target_type() != "lib":
259  str_ing = "Can only combine library targets (type: " + self.get_target_type() + "; target: " + self.get_target_name_root() + ")"
260  raise str_ing
261 
262  for a_file in other_target._lib_files_to_add:
263  self._lib_files_to_add.append (a_file)
264 
265  #
266  # get_project_file
267  #
268  # Return our project file.
269  #
270  def get_project_file (self):
271  (target_name, type) = os.path.splitext (self.get_target_name_root())
272  return self.get_project_file_dir() + "\\" + target_name + ".dsp"
273 
274  #
275  # get_header_files
276  #
277  # Return the list of header files this guy includes
278  #
279  def get_header_files (self):
280  return self._header_files
281 
282  #
283  # get_project_file_dir
284  #
285  # Return the directory that the project file is located in.
286  #
288  return self._newrel_directory + "\\ide\\" + self._bfarch + "\\" + self.get_package_name()
289 
290  #
291  # create_ide_directory
292  #
293  # Make sure that a directory sitting under the ide directory exists. If it
294  # does not, then create it.
295  #
296  def create_ide_directory (self, dir_name):
297  dir_path = self.get_project_file_dir() + "\\" + dir_name
298  if not os.path.exists (dir_path):
299  os.mkdir (dir_path)
300 
301  #
302  # get_package_name
303  #
304  # Return the package we are involved with/in... Unfortunately,
305  # the package name can be burried in several different spots.
306  # -- the working directory could be one of the following two
307  # forms:
308  # d0me\test
309  # tmp\CYGWIN32_NT\d0me
310  # We have to pick the package name out of there correctly. The
311  # method used below isn't very safe...
312  #
313  # normally this is supplied by the build commands. Complain if it isn't.
314  #
315  def get_package_name (self):
316  if self._package_name == "":
317  print "Warning: will attempt to guess the package name (compile commands should have given it)..."
318  if regex.search("^tmp.*$", self._working_dir) == 0:
319  pkg_finder = regex.compile ("^tmp\\\\[^\\]*\\\\\([^\\]*\).*$")
320  if pkg_finder.match (self._working_dir) != -1:
321  self._package_name = pkg_finder.group(1)
322  else:
323  raise "Working dir dosen't look right!"
324  else:
325  old_root = ""
326  root = self._working_dir
327  while root != "":
328  old_root = root
329  (root, stuff) = os.path.split (root)
330  self._package_name = old_root
331  print " Guessed " + self._package_name
332  return self._package_name
333 
334 
335  #
336  # get_working_dir_rel
337  #
338  # Returnt the relative working directory
339  #
341  return self._working_dir
342 
343  #
344  # get_project_ide_name
345  #
346  # Return the name of this target as a project that it will be called in the ide.
347  # This isn't a valid filename, just the text string used by the IDE.
348  # The IDE can't handle "-" in its project names, so replace them with
349  # underscores.
350  #
352  temp = self.get_package_name() + "/" + self.get_target_root_file()
353  return regsub.gsub ("-", "_", temp)
354 
355  #
356  # has_special_commands
357  #
358  # Return true if there are special commands associated with this target
359  #
361  return len(self._special_commands) > 0
362 
363  #
364  # get_special_commands
365  #
366  # Return the list of commands
367  #
369  return self._special_commands
370 
371  #
372  # get_dependent_on_projects
373  #
374  # Return a list of projects on whom we are dependent. Ugh.
375  #
376  def get_dependent_on_projects (self, all_project_objects):
377  list_1 = find_dependent_projects (self._source_files, all_project_objects)
378  list_2 = find_dependent_projects (self._lib_files_to_add, all_project_objects)
379 
380  for duh in list_2:
381  list_1.append(duh)
382 
383  return list_1
384 
385  #
386  # traverse_source_files
387  #
388  # Traverse the network of source files, calling the helper object each time
389  # we get a new one.
390  #
391  # The interface for the helper object. It must have a method "source_file"
392  # that takes two arguments, one a target and one a source file name. The object
393  # will only be called once for every source file.
394  #
395  # Returns the modified object.
396  #
397  def traverse_source_files (self, helper_obj, target_list):
398  done_list = []
399  result = self.do_traverse_source_files (done_list, helper_obj, target_list)
400  return result
401 
402  #
403  # do_traverse_source_files
404  #
405  # The work routine -- don't call this, call traverse_source_files instead.
406  #
407  def do_traverse_source_files (self, done_list, helper_obj, target_list):
408 
409  list_1 = self._source_files
410  for a_file in self._lib_files_to_add:
411  list_1.append (a_file)
412 
413  for a_file in list_1:
414  if target_list.has_key(a_file):
415  if not is_a_project (target_list[a_file].get_target_type()):
416  helper_obj = target_list[a_file].do_traverse_source_files (done_list, helper_obj, target_list)
417  else:
418  if not os.path.isabs (a_file):
419  the_file = self._newrel_directory + "\\" + self._working_dir + "\\" + a_file
420  else:
421  the_file = a_file
422  if the_file not in done_list:
423  helper_obj.source_file (the_file, self)
424  done_list.append(the_file)
425  return helper_obj
426 
427  #
428  # get_source_files
429  #
430  # We look at our list and see if we can determine what source files when into building
431  # this particular target. A .lib file is ignored -- it will be included as a seperate
432  # project.
433  #
434  def get_source_files (self, target_list):
435  src_helper = get_source_file_helper()
436  self.traverse_source_files (src_helper, target_list)
437  return src_helper.source_list()
438 
439  # source_list = []
440  #
441  # list_1 = self._source_files
442  # for a_file in self._lib_files_to_add:
443  # list_1.append(a_file)
444 
445  # for a_file in list_1:
446  # if target_list.has_key(a_file):
447  # if not is_a_project (target_list[a_file].get_target_type()):
448  # target_source_list = target_list[a_file].get_source_files (target_list)
449  # for more_files in target_source_list:
450  # if more_files not in list_1:
451  # list_1.append (more_files)
452  # else:
453  # if not os.path.isabs (a_file):
454  # the_file = self._newrel_directory + "\\" + self._working_dir + "\\" + a_file
455  # else:
456  # the_file = a_file
457  # source_list.append (the_file)
458 
459  # return source_list
460 
461  #
462  # get_target_source_file_list
463  #
464  # Return the list of source files (not lib files)
465  #
467  return self._source_files
468 
469  #
470  # set_source_file_list
471  #
472  # Reset the source file list to some new list
473  #
474  def set_source_file_list (self, new_list):
475  self._source_files = new_list
476 
477  #
478  # add_source_file
479  #
480  # Make sure to add a new source file. Depending upon its type, put it in the correct list.
481  #
482  def add_source_file (self, new_file):
483  t_type = srt_path_util.file_type (new_file)
484  if t_type in source_file_types:
485  self._source_files.append (new_file)
486  else:
487  self._lib_files_to_add.append (new_file)
488 
489  #
490  # get_non_project_targets
491  #
492  # Return the project targets that aren't an individual project in themselves.
493  #
494  def get_non_project_targets (self, target_list):
495  found_targets = []
496 
497  list_1 = self._source_files
498  for a_file in self._lib_files_to_add:
499  list_1.append(a_file)
500 
501  for a_file in list_1:
502  if target_list.has_key(a_file):
503  if not is_a_project (target_list[a_file].get_target_type()):
504  found_targets.append(a_file)
505 
506  target_source_list = target_list[a_file].get_source_files (target_list)
507  for more_files in target_source_list:
508  if more_files not in list_1:
509  list_1.append (more_files)
510 
511  return found_targets
512 
513  #
514  # get_options_list
515  #
516  # Return the options list
517  #
518  def get_options_list (self):
519  if self._forced_cpp_files.has_key(self._source_files[0]):
520  temp = self._option_list
521  temp.append("TP")
522  return temp
523  else:
524  return self._option_list
525 
526  #
527  # are_options_compatible
528  #
529  # Return true if the options listed are compatible with the options this
530  # guy was built with.
531  #
532  def are_options_compatible (self, option_list):
533  for option in option_list:
534  if option not in self._option_list:
535  return 0
536  return 1
537 
538  #
539  # get_include_list
540  #
541  # Return the include directory list
542  #
543  def get_include_list (self):
544  return self._include_paths
545 
546  #
547  # get_unix_include_list
548  #
549  # Same thing, but return the unix include path list
550  #
552  return self._unix_include_paths
553 
554  #
555  # get_macro_define_list
556  #
557  # Return the defined macros
558  #
560  return self._macro_definitions
561 
562  #
563  # get_link_libraries
564  #
565  # Return the list of libraries we need to link to to build this thing.
566  # Try to use the link library search path to find them
567  #
568  def get_link_libraries (self):
569  list_of_libs = []
570  for a_lib in self._link_library_files:
571  lib_file = a_lib
572  if not os.path.exists (a_lib):
573  for search_path in self._library_search_paths:
574  temp = search_path + "\\" + a_lib
575  if os.path.exists (temp):
576  lib_file = temp
577  break
578 
579  list_of_libs.append(lib_file)
580 
581  return self._link_library_files
582 
583  #
584  # get_link_options
585  #
586  # Return the link options
587  #
588  def get_link_options (self):
589  return self._link_options
590 
591  #
592  # set_link_libraries
593  #
594  # Set a new list of link libraries
595  #
596  def set_link_libraries (self, new_list):
597  self._link_library_files = new_list
598 
599  #
600  # get_library_search_paths
601  #
602  # Return the search paths for a library
603  #
605  return self._library_search_paths
606 
607 #
608 # find_dependent_projects
609 #
610 # This guy will search through a list of files and extract those that are dependent
611 # projects. That is, this is a list of dependents. Some of them are going to be made into
612 # a project... which ones so we can establish project dependencies.
613 #
614 # NOTE that at the moment I don't take into account library search paths, so that could
615 # lead to some problems with links! I suspect this should be handled some other place in
616 # this script, not here, however.
617 #
618 def find_dependent_projects (file_name_list, all_projects):
619  found_list = []
620 
621  for file_name in file_name_list:
622  if all_projects.has_key(file_name):
623  t_type = all_projects[file_name].get_target_type()
624  if is_a_project (t_type):
625  found_list.append (file_name)
626 
627  return found_list
628 
629 #
630 # is_a_project
631 #
632 # Return true if this guy is a project
633 #
634 def is_a_project (project_type):
635  return (project_type == "lib") or (project_type == "exe") or (project_type == "")
636 
637 #
638 # get_file_class
639 #
640 # Returns the class of a source file
641 #
642 def get_file_class (filename):
643  file_class = ""
644  pos = regex.search ("\.[^\.]*$", filename)
645  if pos == -1:
646  file_type = "exe"
647  else:
648  file_type = filename[pos+1:]
649 
650  if file_type in header_file_types:
651  return "hpp"
652 
653  for a_target_class in source_file_classes.keys():
654  if file_type in source_file_classes[a_target_class]:
655  file_class = a_target_class
656  return file_class
657 
658 #
659 # get_source_file_helper
660 #
661 # Helper obj to get the list of source files
662 #
664  def __init__ (self):
666 
667  def source_list (self):
668  return self._source_file_list
669 
670  def source_file (self, a_file, target_obj):
671  self._source_file_list.append (a_file)
def parse_from_file(self, ide_file_handle)
def get_dependent_on_projects(self, all_project_objects)
def __init__(self, ide_file_handle="", newrel_dir="")
def set_build_obj(self, filename)
def is_a_project(project_type)
def do_traverse_source_files(self, done_list, helper_obj, target_list)
def source_file(self, a_file, target_obj)
def find_dependent_projects(file_name_list, all_projects)
def create_ide_directory(self, dir_name)
def get_non_project_targets(self, target_list)
def are_options_compatible(self, option_list)
def add_source_file(self, new_file)
def set_source_file_list(self, new_list)
def set_compile_only(self, do_it)
def combine(self, other_target)
def get_file_class(filename)
def traverse_source_files(self, helper_obj, target_list)
def set_link_libraries(self, new_list)
def get_source_files(self, target_list)