Subversion Repositories DevTools

Rev

Rev 381 | Details | Compare with Previous | 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
 
381 dpurdie 168
#
169
#   Convert the list of source files into object files
170
#   Needed for cleaning
171
#
172
my @obj_files = map { $_ =~ s~\.\w+$~.o~; $_ } @opt_source;
227 dpurdie 173
 
174
#
175
#   Clean any existing build artifacts
381 dpurdie 176
#   The build options to place things in a different diractory are broken.
227 dpurdie 177
#   We must be able to build for multiple targets without confusion so we
178
#   clean, then build, then copy out the bits we need.
179
clean();
180
 
181
#
182
#   Generate a Makefile for use by the driver Builder
183
#   This encapsulates the complete driver build mechanism
184
#
185
create_makefile();
186
 
187
#
188
#   Remove some 'make' environment variables
189
#   The JATS make and the PACKAGE make must not know about each other
190
#
369 dpurdie 191
foreach my $var (qw ( MAKE MAKEFLAGS MAKEOVERRIDES MAKELEVEL MAKE_MODE
255 dpurdie 192
                     CC CXX CPP EXTRA_CFLAGS CFLAGS ASFLAGS LDFLAGS
227 dpurdie 193
                     DEBFLAGS LDDINC DEBUG KERNELRELEASE LDDINC
369 dpurdie 194
                     ))
227 dpurdie 195
{
196
    delete $ENV{$var};
197
}
198
 
199
#
200
#   Build up the make command
201
#   Create an array of arguments - Don't need to escape funny bits
202
#
203
my @make_args = ();
204
push @make_args, "ARCH=$ARCH";
205
push @make_args, "CROSS_COMPILE=$CROSS_COMPILE";
206
push @make_args, "KERNELDIR=$KERNELDIR";
207
push @make_args, "-f", "Kbuild";
208
push @make_args, "V=1" unless ( $opt_show_cmds );
209
 
210
System ( 'make', @make_args );
211
 
212
Error  ("Generated output module file not found: $gen_file") unless ( -f $gen_file );
213
copy ( $gen_file, $opt_output ) || Error ("Cannot copy output file: $opt_output");
214
clean() unless $opt_leavetmp;
215
 
216
Message "Script complete";
217
exit 0;
218
 
219
#-------------------------------------------------------------------------------
220
# Function        : create_makefile
221
#
222
# Description     : Generate a makefile called Kbuild
223
#                   This will be used by the kernel builder to do the hard work
224
#
225
#                   The makefile is created via a template embedded in this file
226
#
227
# Inputs          : None
228
#
229
# Returns         : Creates a file called Kbuild
230
#
231
sub create_makefile
232
{
233
    #
234
    #   Create variables for the data that will be substituted
235
    #
236
    my $driver_line = "obj-m	:= $opt_driver.o";
237
 
238
    my $file_list = "${opt_driver}-objs := @obj_files";
239
    my $debug_line = "DEBUG = y";
240
       $debug_line = "# " . $debug_line unless ( $opt_type eq 'D' );
241
 
242
 
243
    my $filename = "Kbuild";
244
    unlink ($filename);
245
    open (KBUILD, ">", $filename ) || Error ("Cannot generate file: $filename");
246
    while ( <DATA> )
247
    {
248
        $_ =~ s~\s+$~~;
249
 
250
        #
251
        #   Replace the entire line
252
        #
253
        $_ = $debug_line if ( m~__DEBUG_LINE__~ );
254
        $_ = $driver_line if ( m~__DEVICE_NAME__~ );
255
        $_ = $file_list if ( m~__FILE_LIST__~ );
256
        last if ( m~__END__~ );
257
 
258
        if ( m~__DEFINES__~ )
259
        {
260
            print KBUILD "# User definitions\n";
261
            foreach my $line ( @opt_defs )
262
            {
255 dpurdie 263
                print KBUILD "EXTRA_CFLAGS += -D$line\n";
227 dpurdie 264
            }
265
            print KBUILD "# End of User definitions\n";
266
            next;
267
        }
268
 
269
        if ( m~__INCDIR__~ )
270
        {
271
            print KBUILD "# Search Include Directories\n";
272
            foreach my $line ( @opt_incdirs )
273
            {
274
                if ( ! -d $line )
275
                {
276
                    Verbose("Incdir does not exist: $line");
277
                    next;
278
                }
279
 
280
                if ( $line =~ m~^/~ )
281
                {
255 dpurdie 282
                    print KBUILD "EXTRA_CFLAGS += -I$line\n";
227 dpurdie 283
                }
284
                else
285
                {
255 dpurdie 286
                    print KBUILD "EXTRA_CFLAGS += -I\$(PWD)/$line\n";
227 dpurdie 287
                }
288
            }
289
            print KBUILD "# End of User Include Directories\n";
290
            next;
291
        }
292
 
293
 
294
        print KBUILD "$_\n";
295
    }
296
 
297
    close (KBUILD);
298
 
299
}
300
 
301
#-------------------------------------------------------------------------------
302
# Function        : clean
303
#
304
# Description     : Clean up build artifacts
381 dpurdie 305
#                   Need to remove stuff that we build as the the kernel builder
306
#                   doesn't handle multiple platforms
227 dpurdie 307
#
381 dpurdie 308
# Inputs          : Globals: @obj_files
227 dpurdie 309
#
381 dpurdie 310
# Returns         : Nothing
227 dpurdie 311
#
312
sub clean
313
{
381 dpurdie 314
    foreach my $files (qw (*.o *~ core .depend .*.cmd *.ko *.mod.c Kbuild ), @obj_files )
227 dpurdie 315
    {
316
        unlink ( glob ( $files ));
317
    }
318
    rmtree  ( '.tmp_versions' );
319
}
320
 
321
__DATA__
322
#
323
#   This is a generated file
324
#   Do not edit or check into version control
325
################################################################################
326
 
327
# Comment/uncomment the following line to disable/enable debugging
328
DEBUG = y __DEBUG_LINE__
329
 
330
__DEFINES__
331
 
332
__INCDIR__
333
 
255 dpurdie 334
# Add your debugging flag (or not) to EXTRA_CFLAGS
227 dpurdie 335
ifeq ($(DEBUG),y)
336
  DEBFLAGS = -O -g -DDEV_DEBUG # "-O" is needed to expand inlines
337
else
338
  DEBFLAGS = -O2
339
endif
340
 
255 dpurdie 341
EXTRA_CFLAGS += $(DEBFLAGS)
342
EXTRA_CFLAGS += -I$(LDDINC)
227 dpurdie 343
 
344
ifneq ($(KERNELRELEASE),)
345
# call from kernel build system
346
 
347
llcd-objs := __FILE_LIST__
348
obj-m	:= __DEVICE_NAME__
349
 
350
else
351
 
352
KERNELDIR ?= "-- Must be defined by calling makefile"
353
PWD       := $(shell pwd)
354
 
355
modules:
356
	$(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules
357
 
358
endif
359
 
360
depend .depend dep:
255 dpurdie 361
	$(CC) $(EXTRA_CFLAGS) -M *.c > .depend
227 dpurdie 362
 
363
 
364
ifeq (.depend,$(wildcard .depend))
365
include .depend
366
endif
367
 
368
__END__
369
 
370
#-------------------------------------------------------------------------------
371
#   Documentation
372
#
373
 
374
=pod
375
 
361 dpurdie 376
=for htmltoc    MAKEUTIL::
377
 
227 dpurdie 378
=head1 NAME
379
 
380
jats_buildlinux - Build a Linux Device Driver
381
 
382
=head1 SYNOPSIS
383
 
384
perl jats_buildlinux [options] source_files+
385
 
386
 Options:
387
    -help              - brief help message
388
    -help -help        - Detailed help message
389
    -man               - Full documentation
390
    -Output=path       - Path to the output file
391
    -Kernel=path       - Path to the Kernel Headers
392
    -GccPath=path      - Path to the gcc compiler to use
393
    -Arch=name         - Architecture name
394
    -Driver=name       - Base name of the driver to build
395
    -LeaveTmp=num      - Leave tmp files after build
396
    -Verbose=num       - Verbose command output
397
    -Type=[P|D]        - Type of build
398
    -Platform=name     - Target Platform
399
    -Define=text       - Definitions to pass to compiler
400
    -Incdir=path       - Extend the header file search path
401
 
402
 
403
=head1 OPTIONS
404
 
405
=over 8
406
 
407
=item B<-help>
408
 
409
Print a brief help message and exits.
410
 
411
=item B<-help -help>
412
 
413
Print a detailed help message with an explanation for each option.
414
 
415
=item B<-man>
416
 
417
Prints the manual page and exits.
418
 
361 dpurdie 419
=back
227 dpurdie 420
 
421
=head1 DESCRIPTION
422
 
423
This program is used internally by Jats to implement the body of the MakeLinuxDriver
424
directive. The command is not intended to be called by the user.
425
 
426
=head1 EXAMPLE
427
 
428
    MakeLinuxDriver ('*', 'llcd.ko',
429
                          '--KernelPackage=linux_kernel_headers', @CSRCS );
430
 
431
 
432
=cut
433