Subversion Repositories DevTools

Rev

Rev 227 | Rev 273 | Go to most recent revision | 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 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 );
255 dpurdie 132
   $ARCH = 'powerpc' if ( $opt_arch =~ m/powerpc/i );
227 dpurdie 133
   Error ("Cannot determine architecture") unless ( $ARCH );
134
 
135
#
136
#   Source files
137
#   These may be comma seperated. Expand the array
138
#
139
@opt_source = @ARGV;
140
Error ("No source files specified" ) unless ( @opt_source );
141
 
142
#
143
#   Must have a nice name for the driver
144
#
145
Error ("No driver name specified") unless ( $opt_driver );
146
 
147
 
148
Message    "======================================================================";
149
Message    "Build Linux Device Driver using the native build method";
150
Message    "         Driver : $opt_driver";
151
Message    "          Arch  : $ARCH";
152
Message    "          Type  : $opt_type";
153
Message    "         Output : $opt_output";
154
Message    "       Platform : $opt_platform";
155
Message    " Cross Compiler : $CROSS_COMPILE";
156
Message    " Kernel Headers : $KERNELDIR";
157
Message    "         Source : @opt_source";
158
foreach  ( @opt_defs )
159
{
160
    Message    "         Define : $_";
161
}
162
foreach  ( @opt_incdirs )
163
{
164
    Message    "         Incdir : $_";
165
}
166
 
167
Message    "======================================================================";
168
 
169
 
170
#
171
#   Clean any existing build artifacts
172
#   The build optiosn to place things in a different diractory are broken.
173
#   We must be able to build for multiple targets without confusion so we
174
#   clean, then build, then copy out the bits we need.
175
clean();
176
 
177
#
178
#   Generate a Makefile for use by the driver Builder
179
#   This encapsulates the complete driver build mechanism
180
#
181
create_makefile();
182
 
183
#
184
#   Remove some 'make' environment variables
185
#   The JATS make and the PACKAGE make must not know about each other
186
#
187
foreach my $var qw ( MAKE MAKEFLAGS MAKEOVERRIDES MAKELEVEL MAKE_MODE
255 dpurdie 188
                     CC CXX CPP EXTRA_CFLAGS CFLAGS ASFLAGS LDFLAGS
227 dpurdie 189
                     DEBFLAGS LDDINC DEBUG KERNELRELEASE LDDINC
190
                     )
191
{
192
    delete $ENV{$var};
193
}
194
 
195
#
196
#   Build up the make command
197
#   Create an array of arguments - Don't need to escape funny bits
198
#
199
my @make_args = ();
200
push @make_args, "ARCH=$ARCH";
201
push @make_args, "CROSS_COMPILE=$CROSS_COMPILE";
202
push @make_args, "KERNELDIR=$KERNELDIR";
203
push @make_args, "-f", "Kbuild";
204
push @make_args, "V=1" unless ( $opt_show_cmds );
205
 
206
System ( 'make', @make_args );
207
 
208
Error  ("Generated output module file not found: $gen_file") unless ( -f $gen_file );
209
copy ( $gen_file, $opt_output ) || Error ("Cannot copy output file: $opt_output");
210
clean() unless $opt_leavetmp;
211
 
212
Message "Script complete";
213
exit 0;
214
 
215
#-------------------------------------------------------------------------------
216
# Function        : create_makefile
217
#
218
# Description     : Generate a makefile called Kbuild
219
#                   This will be used by the kernel builder to do the hard work
220
#
221
#                   The makefile is created via a template embedded in this file
222
#
223
# Inputs          : None
224
#
225
# Returns         : Creates a file called Kbuild
226
#
227
sub create_makefile
228
{
229
    #
230
    #   Create variables for the data that will be substituted
231
    #
232
    my $driver_line = "obj-m	:= $opt_driver.o";
233
 
234
    #
235
    #   Convert the list of source files into object files
236
    #
237
    my @obj_files = map { $_ =~ s~\..*$~.o~; $_ } @opt_source;
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
305
#                   That was done in a makefile, buts its quicker todo it
306
#                   internally
307
#
308
# Inputs          :
309
#
310
# Returns         :
311
#
312
sub clean
313
{
314
    foreach my $files qw (*.o *~ core .depend .*.cmd *.ko *.mod.c Kbuild )
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
 
376
=head1 NAME
377
 
378
jats_buildlinux - Build a Linux Device Driver
379
 
380
=head1 SYNOPSIS
381
 
382
perl jats_buildlinux [options] source_files+
383
 
384
 Options:
385
    -help              - brief help message
386
    -help -help        - Detailed help message
387
    -man               - Full documentation
388
    -Output=path       - Path to the output file
389
    -Kernel=path       - Path to the Kernel Headers
390
    -GccPath=path      - Path to the gcc compiler to use
391
    -Arch=name         - Architecture name
392
    -Driver=name       - Base name of the driver to build
393
    -LeaveTmp=num      - Leave tmp files after build
394
    -Verbose=num       - Verbose command output
395
    -Type=[P|D]        - Type of build
396
    -Platform=name     - Target Platform
397
    -Define=text       - Definitions to pass to compiler
398
    -Incdir=path       - Extend the header file search path
399
 
400
 
401
=head1 OPTIONS
402
 
403
=over 8
404
 
405
=item B<-help>
406
 
407
Print a brief help message and exits.
408
 
409
=item B<-help -help>
410
 
411
Print a detailed help message with an explanation for each option.
412
 
413
=item B<-man>
414
 
415
Prints the manual page and exits.
416
 
417
 
418
=head1 DESCRIPTION
419
 
420
This program is used internally by Jats to implement the body of the MakeLinuxDriver
421
directive. The command is not intended to be called by the user.
422
 
423
=head1 EXAMPLE
424
 
425
    MakeLinuxDriver ('*', 'llcd.ko',
426
                          '--KernelPackage=linux_kernel_headers', @CSRCS );
427
 
428
 
429
=cut
430