Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
#! perl
2
########################################################################
3
# Copyright (C) 2006 ERG Limited, All rights reserved
4
#
5
# Module name   : jats_buildlinux.pl
6
# Module type   : Makefile system
7
# Compiler(s)   : n/a
8
# Environment(s): jats
9
#
10
# Description   : A utility to assist in building Linux Device Driver
11
#                 This script implemenst the runtime functionality of the
12
#                 MakeLinuxDriver directive
13
#
14
# Usage:
15
#
16
#......................................................................#
17
 
255 dpurdie 18
require 5.006_001;
227 dpurdie 19
use strict;
20
use warnings;
21
use Cwd;
22
use FileUtils;
23
use JatsSystem;
24
use JatsError;
25
use ArrayHashUtils;
26
use File::Path;
27
use File::Copy;
28
use Getopt::Long;
29
use Pod::Usage;                             # required for help support
30
 
31
#
32
#   Initialise and configure some of the used packages
33
#
34
ErrorConfig( 'name' => 'BuildLinuxDriver' );
35
SystemConfig ( 'ExitOnError' => 1);
36
InitFileUtils();
37
 
38
#
39
#   Global variables
40
#
41
my $VERSION = "1.0.0";                      # Update this
42
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
43
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
44
my $opt_help = 0;
45
my $opt_manual = 0;
46
my $opt_output;
47
my $opt_kernel;
48
my $opt_gcc_path;
49
my $opt_arch;
50
my @opt_source;
51
my $opt_driver;
52
my $opt_leavetmp;
53
my $opt_show_cmds;
54
my $opt_type = 'P';
55
my $opt_platform;
56
my @opt_defs;
57
my @opt_incdirs;
58
 
59
#
60
#   Extract arguments
61
#
62
my $result = GetOptions (
63
                "help+"         => \$opt_help,              # flag, multiple use allowed
64
                "manual"        => \$opt_manual,            # flag, multiple use allowed
65
                "verbose+"      => \$opt_verbose,           # flag, multiple use allowed
66
                "Output=s"      => \$opt_output,
67
                "GccPath=s"     => \$opt_gcc_path,
68
                "Arch=s"        => \$opt_arch,
69
                "Driver=s"      => \$opt_driver,
70
                "LeaveTmp:s"    => \$opt_leavetmp,
71
                "Verbose:s"     => \$opt_show_cmds,
72
                "Type=s"        => \$opt_type,
73
                "Platform=s"    => \$opt_platform,
74
                "Define=s"      => \@opt_defs,
75
                "Define=s"      => \@opt_defs,
76
                "Incdir=s"      => \@opt_incdirs,
77
                );
78
 
79
#
80
#   Process help and manual options
81
#
82
pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);
83
pod2usage(-verbose => 1) if ($opt_help == 2 );
84
pod2usage(-verbose => 2) if ($opt_manual || ($opt_help > 2));
85
#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ( $#ARGV >= 0 );
86
 
87
#
88
#   Sanity Test user input
89
#
90
Error ("No Output File specified") unless ( $opt_output );
91
 
92
#
93
#   Locate the Kernel Headers
94
#   This will be provided by one of the external packages
95
#   Paths to the packages will be in @opt_incdirs
96
#   Look for a dir ectory with a 'Makefile' - use the first one
97
#
98
my $KERNELDIR;
99
foreach  ( @opt_incdirs )
100
{
101
    my $test_dir = $_ . '/' . $opt_platform;
102
    next unless ( -d $test_dir );
103
    next unless ( -f $test_dir . '/Makefile' );
104
    $KERNELDIR = $test_dir;
105
}
106
Error ("Could not find the Kernel Headers",
107
       "Need a package that contains include/$opt_platform/Makefile"
108
      ) unless ( $KERNELDIR );
109
 
110
 
111
#
112
#   Calculate required bits
113
#   The generated file. Based on the name of the desired output file and the
114
#   source path.
115
#
116
my $gen_file = StripDir($opt_output);
117
 
118
#
119
#   Cross-compiler toolchain root
120
#   Based on GccPath, remove the gcc bit
121
#
122
my $CROSS_COMPILE = $opt_gcc_path;
123
   $CROSS_COMPILE =~ s~-gcc$~-~;
124
 
125
#
126
#   The required architecture
127
#
128
my $ARCH;
129
   $ARCH = 'arm'  if ( $opt_arch =~ m/arm/i );
130
   $ARCH = 'i386' if ( $opt_arch =~ m/i386/i );
255 dpurdie 131
   $ARCH = 'powerpc' if ( $opt_arch =~ m/powerpc/i );
227 dpurdie 132
   Error ("Cannot determine architecture") unless ( $ARCH );
133
 
134
#
135
#   Source files
136
#   These may be comma seperated. Expand the array
137
#
138
@opt_source = @ARGV;
139
Error ("No source files specified" ) unless ( @opt_source );
140
 
141
#
142
#   Must have a nice name for the driver
143
#
144
Error ("No driver name specified") unless ( $opt_driver );
145
 
146
 
147
Message    "======================================================================";
148
Message    "Build Linux Device Driver using the native build method";
149
Message    "         Driver : $opt_driver";
150
Message    "          Arch  : $ARCH";
151
Message    "          Type  : $opt_type";
152
Message    "         Output : $opt_output";
153
Message    "       Platform : $opt_platform";
154
Message    " Cross Compiler : $CROSS_COMPILE";
155
Message    " Kernel Headers : $KERNELDIR";
156
Message    "         Source : @opt_source";
157
foreach  ( @opt_defs )
158
{
159
    Message    "         Define : $_";
160
}
161
foreach  ( @opt_incdirs )
162
{
163
    Message    "         Incdir : $_";
164
}
165
 
166
Message    "======================================================================";
167
 
168
 
169
#
170
#   Clean any existing build artifacts
171
#   The build optiosn to place things in a different diractory are broken.
172
#   We must be able to build for multiple targets without confusion so we
173
#   clean, then build, then copy out the bits we need.
174
clean();
175
 
176
#
177
#   Generate a Makefile for use by the driver Builder
178
#   This encapsulates the complete driver build mechanism
179
#
180
create_makefile();
181
 
182
#
183
#   Remove some 'make' environment variables
184
#   The JATS make and the PACKAGE make must not know about each other
185
#
369 dpurdie 186
foreach my $var (qw ( MAKE MAKEFLAGS MAKEOVERRIDES MAKELEVEL MAKE_MODE
255 dpurdie 187
                     CC CXX CPP EXTRA_CFLAGS CFLAGS ASFLAGS LDFLAGS
227 dpurdie 188
                     DEBFLAGS LDDINC DEBUG KERNELRELEASE LDDINC
369 dpurdie 189
                     ))
227 dpurdie 190
{
191
    delete $ENV{$var};
192
}
193
 
194
#
195
#   Build up the make command
196
#   Create an array of arguments - Don't need to escape funny bits
197
#
198
my @make_args = ();
199
push @make_args, "ARCH=$ARCH";
200
push @make_args, "CROSS_COMPILE=$CROSS_COMPILE";
201
push @make_args, "KERNELDIR=$KERNELDIR";
202
push @make_args, "-f", "Kbuild";
203
push @make_args, "V=1" unless ( $opt_show_cmds );
204
 
205
System ( 'make', @make_args );
206
 
207
Error  ("Generated output module file not found: $gen_file") unless ( -f $gen_file );
208
copy ( $gen_file, $opt_output ) || Error ("Cannot copy output file: $opt_output");
209
clean() unless $opt_leavetmp;
210
 
211
Message "Script complete";
212
exit 0;
213
 
214
#-------------------------------------------------------------------------------
215
# Function        : create_makefile
216
#
217
# Description     : Generate a makefile called Kbuild
218
#                   This will be used by the kernel builder to do the hard work
219
#
220
#                   The makefile is created via a template embedded in this file
221
#
222
# Inputs          : None
223
#
224
# Returns         : Creates a file called Kbuild
225
#
226
sub create_makefile
227
{
228
    #
229
    #   Create variables for the data that will be substituted
230
    #
231
    my $driver_line = "obj-m	:= $opt_driver.o";
232
 
233
    #
234
    #   Convert the list of source files into object files
235
    #
236
    my @obj_files = map { $_ =~ s~\..*$~.o~; $_ } @opt_source;
237
    my $file_list = "${opt_driver}-objs := @obj_files";
238
    my $debug_line = "DEBUG = y";
239
       $debug_line = "# " . $debug_line unless ( $opt_type eq 'D' );
240
 
241
 
242
    my $filename = "Kbuild";
243
    unlink ($filename);
244
    open (KBUILD, ">", $filename ) || Error ("Cannot generate file: $filename");
245
    while ( <DATA> )
246
    {
247
        $_ =~ s~\s+$~~;
248
 
249
        #
250
        #   Replace the entire line
251
        #
252
        $_ = $debug_line if ( m~__DEBUG_LINE__~ );
253
        $_ = $driver_line if ( m~__DEVICE_NAME__~ );
254
        $_ = $file_list if ( m~__FILE_LIST__~ );
255
        last if ( m~__END__~ );
256
 
257
        if ( m~__DEFINES__~ )
258
        {
259
            print KBUILD "# User definitions\n";
260
            foreach my $line ( @opt_defs )
261
            {
255 dpurdie 262
                print KBUILD "EXTRA_CFLAGS += -D$line\n";
227 dpurdie 263
            }
264
            print KBUILD "# End of User definitions\n";
265
            next;
266
        }
267
 
268
        if ( m~__INCDIR__~ )
269
        {
270
            print KBUILD "# Search Include Directories\n";
271
            foreach my $line ( @opt_incdirs )
272
            {
273
                if ( ! -d $line )
274
                {
275
                    Verbose("Incdir does not exist: $line");
276
                    next;
277
                }
278
 
279
                if ( $line =~ m~^/~ )
280
                {
255 dpurdie 281
                    print KBUILD "EXTRA_CFLAGS += -I$line\n";
227 dpurdie 282
                }
283
                else
284
                {
255 dpurdie 285
                    print KBUILD "EXTRA_CFLAGS += -I\$(PWD)/$line\n";
227 dpurdie 286
                }
287
            }
288
            print KBUILD "# End of User Include Directories\n";
289
            next;
290
        }
291
 
292
 
293
        print KBUILD "$_\n";
294
    }
295
 
296
    close (KBUILD);
297
 
298
}
299
 
300
#-------------------------------------------------------------------------------
301
# Function        : clean
302
#
303
# Description     : Clean up build artifacts
304
#                   That was done in a makefile, buts its quicker todo it
305
#                   internally
306
#
307
# Inputs          :
308
#
309
# Returns         :
310
#
311
sub clean
312
{
369 dpurdie 313
    foreach my $files (qw (*.o *~ core .depend .*.cmd *.ko *.mod.c Kbuild ))
227 dpurdie 314
    {
315
        unlink ( glob ( $files ));
316
    }
317
    rmtree  ( '.tmp_versions' );
318
}
319
 
320
__DATA__
321
#
322
#   This is a generated file
323
#   Do not edit or check into version control
324
################################################################################
325
 
326
# Comment/uncomment the following line to disable/enable debugging
327
DEBUG = y __DEBUG_LINE__
328
 
329
__DEFINES__
330
 
331
__INCDIR__
332
 
255 dpurdie 333
# Add your debugging flag (or not) to EXTRA_CFLAGS
227 dpurdie 334
ifeq ($(DEBUG),y)
335
  DEBFLAGS = -O -g -DDEV_DEBUG # "-O" is needed to expand inlines
336
else
337
  DEBFLAGS = -O2
338
endif
339
 
255 dpurdie 340
EXTRA_CFLAGS += $(DEBFLAGS)
341
EXTRA_CFLAGS += -I$(LDDINC)
227 dpurdie 342
 
343
ifneq ($(KERNELRELEASE),)
344
# call from kernel build system
345
 
346
llcd-objs := __FILE_LIST__
347
obj-m	:= __DEVICE_NAME__
348
 
349
else
350
 
351
KERNELDIR ?= "-- Must be defined by calling makefile"
352
PWD       := $(shell pwd)
353
 
354
modules:
355
	$(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules
356
 
357
endif
358
 
359
depend .depend dep:
255 dpurdie 360
	$(CC) $(EXTRA_CFLAGS) -M *.c > .depend
227 dpurdie 361
 
362
 
363
ifeq (.depend,$(wildcard .depend))
364
include .depend
365
endif
366
 
367
__END__
368
 
369
#-------------------------------------------------------------------------------
370
#   Documentation
371
#
372
 
373
=pod
374
 
361 dpurdie 375
=for htmltoc    MAKEUTIL::
376
 
227 dpurdie 377
=head1 NAME
378
 
379
jats_buildlinux - Build a Linux Device Driver
380
 
381
=head1 SYNOPSIS
382
 
383
perl jats_buildlinux [options] source_files+
384
 
385
 Options:
386
    -help              - brief help message
387
    -help -help        - Detailed help message
388
    -man               - Full documentation
389
    -Output=path       - Path to the output file
390
    -Kernel=path       - Path to the Kernel Headers
391
    -GccPath=path      - Path to the gcc compiler to use
392
    -Arch=name         - Architecture name
393
    -Driver=name       - Base name of the driver to build
394
    -LeaveTmp=num      - Leave tmp files after build
395
    -Verbose=num       - Verbose command output
396
    -Type=[P|D]        - Type of build
397
    -Platform=name     - Target Platform
398
    -Define=text       - Definitions to pass to compiler
399
    -Incdir=path       - Extend the header file search path
400
 
401
 
402
=head1 OPTIONS
403
 
404
=over 8
405
 
406
=item B<-help>
407
 
408
Print a brief help message and exits.
409
 
410
=item B<-help -help>
411
 
412
Print a detailed help message with an explanation for each option.
413
 
414
=item B<-man>
415
 
416
Prints the manual page and exits.
417
 
361 dpurdie 418
=back
227 dpurdie 419
 
420
=head1 DESCRIPTION
421
 
422
This program is used internally by Jats to implement the body of the MakeLinuxDriver
423
directive. The command is not intended to be called by the user.
424
 
425
=head1 EXAMPLE
426
 
427
    MakeLinuxDriver ('*', 'llcd.ko',
428
                          '--KernelPackage=linux_kernel_headers', @CSRCS );
429
 
430
 
431
=cut
432