Subversion Repositories DevTools

Rev

Rev 255 | 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
 
18
require 5.6.1;
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 File::Find;
29
use Getopt::Long;
30
use Pod::Usage;                             # required for help support
31
 
32
#
33
#   Initialise and configure some of the used packages
34
#
35
ErrorConfig( 'name' => 'BuildLinuxDriver' );
36
SystemConfig ( 'ExitOnError' => 1);
37
InitFileUtils();
38
 
39
#
40
#   Global variables
41
#
42
my $VERSION = "1.0.0";                      # Update this
43
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
44
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
45
my $opt_help = 0;
46
my $opt_manual = 0;
47
my $opt_output;
48
my $opt_kernel;
49
my $opt_gcc_path;
50
my $opt_arch;
51
my @opt_source;
52
my $opt_driver;
53
my $opt_leavetmp;
54
my $opt_show_cmds;
55
my $opt_type = 'P';
56
my $opt_platform;
57
my @opt_defs;
58
my @opt_incdirs;
59
 
60
#
61
#   Extract arguments
62
#
63
my $result = GetOptions (
64
                "help+"         => \$opt_help,              # flag, multiple use allowed
65
                "manual"        => \$opt_manual,            # flag, multiple use allowed
66
                "verbose+"      => \$opt_verbose,           # flag, multiple use allowed
67
                "Output=s"      => \$opt_output,
68
                "GccPath=s"     => \$opt_gcc_path,
69
                "Arch=s"        => \$opt_arch,
70
                "Driver=s"      => \$opt_driver,
71
                "LeaveTmp:s"    => \$opt_leavetmp,
72
                "Verbose:s"     => \$opt_show_cmds,
73
                "Type=s"        => \$opt_type,
74
                "Platform=s"    => \$opt_platform,
75
                "Define=s"      => \@opt_defs,
76
                "Define=s"      => \@opt_defs,
77
                "Incdir=s"      => \@opt_incdirs,
78
                );
79
 
80
#
81
#   Process help and manual options
82
#
83
pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);
84
pod2usage(-verbose => 1) if ($opt_help == 2 );
85
pod2usage(-verbose => 2) if ($opt_manual || ($opt_help > 2));
86
#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ( $#ARGV >= 0 );
87
 
88
#
89
#   Sanity Test user input
90
#
91
Error ("No Output File specified") unless ( $opt_output );
92
 
93
#
94
#   Locate the Kernel Headers
95
#   This will be provided by one of the external packages
96
#   Paths to the packages will be in @opt_incdirs
97
#   Look for a dir ectory with a 'Makefile' - use the first one
98
#
99
my $KERNELDIR;
100
foreach  ( @opt_incdirs )
101
{
102
    my $test_dir = $_ . '/' . $opt_platform;
103
    next unless ( -d $test_dir );
104
    next unless ( -f $test_dir . '/Makefile' );
105
    $KERNELDIR = $test_dir;
106
}
107
Error ("Could not find the Kernel Headers",
108
       "Need a package that contains include/$opt_platform/Makefile"
109
      ) unless ( $KERNELDIR );
110
 
111
 
112
#
113
#   Calculate required bits
114
#   The generated file. Based on the name of the desired output file and the
115
#   source path.
116
#
117
my $gen_file = StripDir($opt_output);
118
 
119
#
120
#   Cross-compiler toolchain root
121
#   Based on GccPath, remove the gcc bit
122
#
123
my $CROSS_COMPILE = $opt_gcc_path;
124
   $CROSS_COMPILE =~ s~-gcc$~-~;
125
 
126
#
127
#   The required architecture
128
#
129
my $ARCH;
130
   $ARCH = 'arm'  if ( $opt_arch =~ m/arm/i );
131
   $ARCH = 'i386' if ( $opt_arch =~ m/i386/i );
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
#
186
foreach my $var qw ( MAKE MAKEFLAGS MAKEOVERRIDES MAKELEVEL MAKE_MODE
187
                     CC CXX CPP CFLAGS ASFLAGS LDFLAGS
188
                     DEBFLAGS LDDINC DEBUG KERNELRELEASE LDDINC
189
                     )
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
            {
262
                print KBUILD "CFLAGS += -D$line\n";
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
                {
281
                    print KBUILD "CFLAGS += -I$line\n";
282
                }
283
                else
284
                {
285
                    print KBUILD "CFLAGS += -I\$(PWD)/$line\n";
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
{
313
    foreach my $files qw (*.o *~ core .depend .*.cmd *.ko *.mod.c Kbuild )
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
 
333
# Add your debugging flag (or not) to CFLAGS
334
ifeq ($(DEBUG),y)
335
  DEBFLAGS = -O -g -DDEV_DEBUG # "-O" is needed to expand inlines
336
else
337
  DEBFLAGS = -O2
338
endif
339
 
340
CFLAGS += $(DEBFLAGS)
341
CFLAGS += -I$(LDDINC)
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:
360
	$(CC) $(CFLAGS) -M *.c > .depend
361
 
362
 
363
ifeq (.depend,$(wildcard .depend))
364
include .depend
365
endif
366
 
367
__END__
368
 
369
#-------------------------------------------------------------------------------
370
#   Documentation
371
#
372
 
373
=pod
374
 
375
=head1 NAME
376
 
377
jats_buildlinux - Build a Linux Device Driver
378
 
379
=head1 SYNOPSIS
380
 
381
perl jats_buildlinux [options] source_files+
382
 
383
 Options:
384
    -help              - brief help message
385
    -help -help        - Detailed help message
386
    -man               - Full documentation
387
    -Output=path       - Path to the output file
388
    -Kernel=path       - Path to the Kernel Headers
389
    -GccPath=path      - Path to the gcc compiler to use
390
    -Arch=name         - Architecture name
391
    -Driver=name       - Base name of the driver to build
392
    -LeaveTmp=num      - Leave tmp files after build
393
    -Verbose=num       - Verbose command output
394
    -Type=[P|D]        - Type of build
395
    -Platform=name     - Target Platform
396
    -Define=text       - Definitions to pass to compiler
397
    -Incdir=path       - Extend the header file search path
398
 
399
 
400
=head1 OPTIONS
401
 
402
=over 8
403
 
404
=item B<-help>
405
 
406
Print a brief help message and exits.
407
 
408
=item B<-help -help>
409
 
410
Print a detailed help message with an explanation for each option.
411
 
412
=item B<-man>
413
 
414
Prints the manual page and exits.
415
 
416
 
417
=head1 DESCRIPTION
418
 
419
This program is used internally by Jats to implement the body of the MakeLinuxDriver
420
directive. The command is not intended to be called by the user.
421
 
422
=head1 EXAMPLE
423
 
424
    MakeLinuxDriver ('*', 'llcd.ko',
425
                          '--KernelPackage=linux_kernel_headers', @CSRCS );
426
 
427
 
428
=cut
429