Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
107 bj 1
package AutomakeWorkspaceCreator;
2
 
3
# ************************************************************
4
# Description   : A Automake Workspace (Makefile) creator
5
# Author        : J.T. Conklin & Steve Huston
6
# Create Date   : 5/13/2002
7
# ************************************************************
8
 
9
# ************************************************************
10
# Pragmas
11
# ************************************************************
12
 
13
use strict;
14
 
15
use AutomakeProjectCreator;
16
use WorkspaceCreator;
17
use WorkspaceHelper;
18
 
19
use vars qw(@ISA);
20
@ISA = qw(WorkspaceCreator);
21
 
22
# ************************************************************
23
# Data Section
24
# ************************************************************
25
 
26
my($acfile)  = 'configure.ac';
27
my($acmfile) = 'configure.ac.Makefiles';
28
 
29
# ************************************************************
30
# Subroutine Section
31
# ************************************************************
32
 
33
sub workspace_file_name {
34
  my($self) = shift;
35
  return $self->get_modified_workspace_name('Makefile', '.am');
36
}
37
 
38
 
39
sub workspace_per_project {
40
  #my($self) = shift;
41
  return 1;
42
}
43
 
44
 
45
sub pre_workspace {
46
  my($self) = shift;
47
  my($fh)   = shift;
48
  my($crlf) = $self->crlf();
49
 
50
  print $fh '##  Process this file with automake to create Makefile.in', $crlf,
51
            '##', $crlf,
198 bj 52
            '## ', '$', 'Id', '$', $crlf,
107 bj 53
            '##', $crlf,
54
            '## This file was generated by MPC.  Any changes made directly to', $crlf,
55
            '## this file will be lost the next time it is generated.', $crlf,
56
            '##', $crlf,
57
            '## MPC Command:', $crlf,
58
            "## $0 @ARGV", $crlf, $crlf;
59
}
60
 
61
 
62
sub write_comps {
63
  my($self)          = shift;
64
  my($fh)            = shift;
65
  my($creator)       = shift;
66
  my($toplevel)      = shift;
67
  my($projects)      = $self->get_projects();
68
  my(@list)          = $self->sort_dependencies($projects);
69
  my($crlf)          = $self->crlf();
70
  my(%unique)        = ();
71
  my(@dirs)          = ();
72
  my(@locals)        = ();
73
  my(%proj_dir_seen) = ();
74
  my($have_subdirs)  = 0;
75
  my($outdir)        = $self->get_outdir();
76
 
77
  ## This step writes a configure.ac.Makefiles list into the starting
78
  ## directory. The list contains of all the Makefiles generated down
79
  ## the tree. configure.ac can include this to get an up-to-date list
80
  ## of all the involved Makefiles.
81
  my($mfh);
82
  if ($toplevel) {
83
    if (! -e "$outdir/$acfile") {
84
      my($acfh) = new FileHandle();
85
      if (open($acfh, ">$outdir/$acfile")) {
86
        print $acfh "AC_INIT(", $self->get_workspace_name(), ", 1.0)$crlf",
87
                    "AM_INIT_AUTOMAKE([1.9])$crlf",
88
                    $crlf,
89
                    "AC_PROG_CXX$crlf",
90
                    "AC_PROG_CXXCPP$crlf",
91
                    "AC_PROG_LIBTOOL$crlf",
92
                    $crlf,
93
                    "m4_include([$acmfile])$crlf",
94
                    $crlf,
95
                    "AC_OUTPUT$crlf";
96
        close($acfh);
97
      }
98
    }
99
    else {
100
      $self->information("$acfile already exists.");
101
    }
102
 
103
    unlink("$outdir/$acmfile");
104
    $mfh = new FileHandle();
105
    open($mfh, ">$outdir/$acmfile");
106
    ## The top-level is never listed as a dependency, so it needs to be
107
    ## added explicitly.
108
    print $mfh "AC_CONFIG_FILES([ Makefile ])$crlf";
109
  }
110
 
111
  ## If we're writing a configure.ac.Makefiles file, every seen project
112
  ## goes into it. Since we only write this at the starting directory
113
  ## level, it'll include all projects processed at this level and below.
114
  foreach my $dep (@list) {
115
    if ($mfh) {
116
      ## There should be a Makefile at each level, but it's not a project,
117
      ## it's a workspace; therefore, it's not in the list of projects.
118
      ## Since we're consolidating all the project files into one workspace
119
      ## Makefile.am per directory level, be sure to add that Makefile.am
120
      ## entry at each level there's a project dependency.
121
      my($dep_dir) = $self->mpc_dirname($dep);
122
      if (!defined $proj_dir_seen{$dep_dir}) {
123
        $proj_dir_seen{$dep_dir} = 1;
124
        ## If there are directory levels between project-containing
125
        ## directories (for example, at this time in
126
        ## ACE_wrappers/apps/JAWS/server, there are no projects at the
127
        ## apps or apps/JAWS level) we need to insert the Makefile
128
        ## entries for the levels without projects. They won't be listed
129
        ## in @list but are needed for make to traverse intervening directory
130
        ## levels down to where the project(s) to build are.
131
        my(@dirs) = split /\//, $dep_dir;
132
        my $inter_dir = "";
133
        foreach my $dep (@dirs) {
134
          $inter_dir = "$inter_dir$dep";
135
          if (!defined $proj_dir_seen{$inter_dir}) {
136
            $proj_dir_seen{$inter_dir} = 1;
137
            print $mfh "AC_CONFIG_FILES([ $inter_dir" . "/Makefile ])$crlf";
138
          }
139
          $inter_dir = "$inter_dir/";
140
        }
141
        print $mfh "AC_CONFIG_FILES([ $dep_dir" . "/Makefile ])$crlf";
142
      }
143
    }
144
 
145
    ## Get a unique list of next-level directories for SUBDIRS.
146
    ## To make sure we keep the dependencies correct, insert the '.' for
147
    ## any local projects in the proper place. Remember if any subdirs
148
    ## are seen to know if we need a SUBDIRS entry generated.
149
    my($dir) = $self->get_first_level_directory($dep);
150
    if (!defined $unique{$dir}) {
151
      $unique{$dir} = 1;
152
      unshift(@dirs, $dir);
153
    }
154
    if ($dir eq '.') {
155
      ## At each directory level, each project is written into a separate
156
      ## Makefile.<project>.am file. To bring these back into the build
157
      ## process, they'll be sucked back into the workspace Makefile.am file.
158
      ## Remember which ones to pull in at this level.
159
      unshift(@locals, $dep);
160
    }
161
    else {
162
      $have_subdirs = 1;
163
    }
164
  }
165
  if ($mfh) {
166
    close($mfh);
167
  }
168
 
169
  # The Makefile.<project>.am files append values to build target macros
170
  # for each program/library to build. When using conditionals, however,
171
  # a plain empty assignment is done outside the conditional to be sure
172
  # that each append can be done regardless of the condition test. Because
173
  # automake fails if the first isn't a plain assignment, we need to resolve
174
  # these situations when combining the files. The code below makes sure
175
  # that there's always a plain assignment, whether it's one outside a
176
  # conditional or the first append is changed to a simple assignment.
177
  #
178
  # We should consider extending this to support all macros that match
179
  # automake's uniform naming convention.  A true perl wizard probably
180
  # would be able to do this in a single line of code.
181
 
182
  my(%seen) = ();
183
  my(%conditional_targets) = ();
184
  my(%unconditional_targets) = ();
185
  my(%first_instance_unconditional) = ();
186
  my($installable_headers) = undef;
187
  my($installable_pkgconfig) = undef;
188
  my($includedir) = undef;
189
  my($project_name) = undef;
190
 
191
  ## To avoid unnecessarily emitting blank assignments, rip through the
192
  ## Makefile.<project>.am files and check for conditions.
193
  if (@locals) {
194
    my($pfh) = new FileHandle();
195
    foreach my $local (reverse @locals) {
196
      if ($local =~ /Makefile\.(.*)\.am/) {
197
        $project_name = $1;
198
      }
199
      else {
200
        $project_name = 'nobase';
201
      }
202
 
203
      if (open($pfh, "$outdir/$local")) {
204
        my($in_condition) = 0;
205
        my($regok)        = $self->escape_regex_special($project_name);
206
        my($inc_pattern)  = $regok . '_include_HEADERS';
207
        my($pkg_pattern)  = $regok . '_pkginclude_HEADERS';
208
        while (<$pfh>) {
209
          # Don't look at comments
210
          next if (/^#/);
211
 
212
          if (/^if\s*/) {
213
            $in_condition++;
214
          }
215
          if (/^endif\s*/) {
216
            $in_condition--;
217
          }
218
 
217 bj 219
          if (   /(^[a-zA-Z][a-zA-Z0-9_]*_(PROGRAMS|LIBRARIES|LTLIBRARIES|LISP|PYTHON|JAVA|SCRIPTS|DATA|SOURCES|HEADERS|MANS|TEXINFOS|LIBADD|LDADD))\s*\+=\s*/
107 bj 220
              || /(^CLEANFILES)\s*\+=\s*/
221
              || /(^EXTRA_DIST)\s*\+=\s*/
222
             ) {
223
 
224
            if ($in_condition) {
225
              $conditional_targets{$1}++;
226
            } else {
227
              if (! $seen{$1} ) {
228
                $first_instance_unconditional{$1} = 1;
229
              }
230
              $unconditional_targets{$1}++;
231
            }
232
            $seen{$1} = 1;
233
 
234
            if (/^pkgconfig_DATA/) {
235
               $installable_pkgconfig= 1;
236
            }
237
            if (/^$inc_pattern\s*\+=\s*/ || /^$pkg_pattern\s*\+=\s*/) {
238
              $installable_headers = 1;
239
            }
240
          }
241
          elsif (/includedir\s*=\s*(.*)/) {
242
            $includedir = $1;
243
          }
244
        }
245
 
246
        close($pfh);
247
        $in_condition = 0;
248
      }
249
      else {
250
        $self->error("Unable to open $local for reading.");
251
      }
252
    }
253
  }
254
 
255
  #
256
  # Clear seen hash
257
  #
258
  %seen = ();
259
 
260
  ## Print out the Makefile.am.
261
  my($wsHelper) = WorkspaceHelper::get($self);
262
  my($convert_header_name) = undef;
263
  if ((!defined $includedir && $installable_headers)
264
      || $installable_pkgconfig) {
265
    if (!defined $includedir && $installable_headers) {
266
      my($incdir) = $wsHelper->modify_value('includedir',
267
                                            $self->get_includedir());
268
      if ($incdir ne '') {
269
        print $fh "includedir = \@includedir\@$incdir$crlf";
270
        $convert_header_name = 1;
271
      }
272
    }
273
    if ($installable_pkgconfig) {
274
       print $fh "pkgconfigdir = \@libdir\@/pkgconfig$crlf";
275
    }
276
 
277
    print $fh $crlf;
278
  }
279
 
280
  if (@locals) {
281
    my($status, $error) = $wsHelper->write_settings($self, $fh, @locals);
282
    if (!$status) {
283
      $self->error($error);
284
    }
285
  }
286
 
287
  ## If there are local projects, insert "." as the first SUBDIR entry.
288
  if ($have_subdirs == 1) {
289
    print $fh 'SUBDIRS =';
290
    foreach my $dir (reverse @dirs) {
291
      print $fh " \\$crlf        $dir";
292
    }
293
    print $fh $crlf, $crlf;
294
  }
295
 
296
  ## Now, for each target used in a conditional, emit a blank assignment
297
  ## and mark that we've seen that target to avoid changing the += to =
298
  ## as the individual files are pulled in.
299
  if (%conditional_targets) {
300
    my $primary;
301
    my $count;
302
 
303
    while ( ($primary, $count) = each %conditional_targets) {
304
      if (! $first_instance_unconditional{$primary}
305
          && ($unconditional_targets{$primary} || ($count > 1)))
306
      {
307
        print $fh "$primary =$crlf";
308
        $seen{$primary} = 1;
309
      }
310
    }
311
 
312
    print $fh $crlf;
313
  }
314
 
315
  ## Take the local Makefile.<project>.am files and insert each one here,
316
  ## then delete it.
317
  if (@locals) {
318
    my($pfh) = new FileHandle();
319
    my($liblocs) = $self->get_lib_locations();
320
    my($here) = $self->getcwd();
321
    my($start) = $self->getstartdir();
322
    foreach my $local (reverse @locals) {
323
 
324
      if (open($pfh, "$outdir/$local")) {
325
        print $fh "## $local", $crlf;
326
 
327
        my($look_for_libs) = 0;
217 bj 328
        my($prev_line) = undef;
107 bj 329
 
330
        while (<$pfh>) {
331
          # Don't emit comments
332
          next if (/^#/);
333
 
334
          if ($convert_header_name) {
335
            if ($local =~ /Makefile\.(.*)\.am/) {
336
              $project_name = $1;
337
            }
338
            else {
339
              $project_name = 'nobase';
340
            }
341
            my($regok)       = $self->escape_regex_special($project_name);
342
            my($inc_pattern) = $regok . '_include_HEADERS';
343
            my($pkg_pattern) = $regok . '_pkginclude_HEADERS';
344
            if (/^$inc_pattern\s*\+=\s*/ || /^$pkg_pattern\s*\+=\s*/) {
345
              $_ =~ s/^$project_name/nobase/;
346
            }
347
          }
348
 
217 bj 349
          if (   /(^[a-zA-Z][a-zA-Z0-9_]*_(PROGRAMS|LIBRARIES|LTLIBRARIES|LISP|PYTHON|JAVA|SCRIPTS|DATA|SOURCES|HEADERS|MANS|TEXINFOS|LIBADD|LDADD))\s*\+=\s*/
107 bj 350
              || /(^CLEANFILES)\s*\+=\s*/
351
              || /(^EXTRA_DIST)\s*\+=\s*/
352
             ) {
353
            if (!defined ($seen{$1})) {
354
              $seen{$1} = 1;
355
              s/\+=/=/;
356
            }
357
          }
358
 
359
          ## This scheme relies on automake.mpd emitting the 'la' libs first.
360
          ## Look for all the libXXXX.la, find out where they are located
361
          ## relative to the start of the MPC run, and relocate the reference
362
          ## to that location under $top_builddir. Unless the referred-to
363
          ## library is in the current directory, then leave it undecorated
364
          ## so the automake-generated dependency orders the build correctly.
365
          if ($look_for_libs) {
366
            my @libs = /\s+(lib(\w+).la)/gm;
367
            my $libcount = @libs / 2;
368
            for(my $i = 0; $i < $libcount; ++$i) {
369
              my $libfile = $libs[$i * 2];
370
              my $libname = $libs[$i * 2 + 1];
371
              my $reldir  = $$liblocs{$libname};
372
              if ($reldir) {
373
                if ("$start/$reldir" ne $here) {
374
                  my($mod) = $wsHelper->modify_libpath($_, $reldir, $libfile);
375
                  if (defined $mod) {
376
                    $_ = $mod;
377
                  }
378
                  else {
379
                    s/$libfile/\$(top_builddir)\/$reldir\/$libfile/;
380
                  }
381
                }
382
              }
383
              else {
384
                $self->warning("No reldir found for $libname ($libfile).");
385
              }
386
            }
387
            if ($libcount == 0) {
388
              $look_for_libs = 0;
389
            }
390
          }
391
          if (/_LDADD = \\$/ || /_LIBADD = \\$/) {
392
            $look_for_libs = 1;
393
          }
394
 
217 bj 395
          ## I have introduced a one line delay so that I can simplify
396
          ## the automake template.  If our current line is empty, then
397
          ## we will remove the trailing backslash before printing the
398
          ## previous line.  Automake is horribly unforgiving so we must
399
          ## avoid this situation at all cost.
400
          if (defined $prev_line) {
401
            $prev_line =~ s/\s*\\$// if ($_ =~ /^\s*$/);
402
            print $fh $prev_line;
403
          }
404
          $prev_line = $_;
107 bj 405
        }
217 bj 406
        ## The one line delay requires that we print out the previous
407
        ## line (if there was one) when we reach the end of the file.
408
        if (defined $prev_line) {
409
          $prev_line =~ s/\s*\\$//;
410
          print $fh $prev_line;
411
        }
107 bj 412
 
413
        close($pfh);
414
        unlink("$outdir/$local");
415
        print $fh $crlf;
416
      }
417
      else {
418
        $self->error("Unable to open $local for reading.");
419
      }
420
    }
421
  }
422
 
423
  ## If this is the top-level Makefile.am, it needs the directives to pass
424
  ## autoconf/automake flags down the tree when running autoconf.
425
  ## *** This may be too closely tied to how we have things set up in ACE,
426
  ## even though it's recommended practice. ***
427
  if ($toplevel) {
428
    print $fh $crlf,
429
              'ACLOCAL = @ACLOCAL@', $crlf,
430
              'ACLOCAL_AMFLAGS = -I m4', $crlf,
431
              'AUTOMAKE_OPTIONS = foreign', $crlf,
432
              $crlf;
433
  }
434
 
435
  ## Finish up with the cleanup specs.
436
  if (@locals) {
437
    ## There is no reason to emit this if there are no local targets.
438
    ## An argument could be made that it shouldn't be emitted in any
439
    ## case because it could be handled by CLEANFILES or a verbatim
440
    ## clause.
441
 
442
    print $fh '## Clean up template repositories, etc.', $crlf,
443
              'clean-local:', $crlf,
444
              "\t-rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*",
445
              $crlf,
446
              "\t-rm -f gcctemp.c gcctemp so_locations *.ics", $crlf,
447
              "\t-rm -rf cxx_repository ptrepository ti_files", $crlf,
448
              "\t-rm -rf templateregistry ir.out", $crlf,
449
              "\t-rm -rf ptrepository SunWS_cache Templates.DB", $crlf;
450
  }
451
}
452
 
453
 
454
sub get_includedir {
455
  my($self)  = shift;
456
  my($value) = $self->getcwd();
457
  my($start) = $self->getstartdir();
458
 
459
  ## Take off the starting directory
460
  $value =~ s/$start//;
461
  return $value;
462
}
463
 
464
1;