Subversion Repositories DevTools

Rev

Rev 5709 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
#! perl
2
########################################################################
6177 dpurdie 3
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
227 dpurdie 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;
5672 dpurdie 58
my $opt_localbindir;
59
my @opt_external_modules;
60
my @opt_external_modules_paths;
61
my $opt_clean;
227 dpurdie 62
 
63
#
64
#   Extract arguments
65
#
66
my $result = GetOptions (
5672 dpurdie 67
                "help+"             => \$opt_help,              # flag, multiple use allowed
68
                "manual"            => \$opt_manual,            # flag, multiple use allowed
69
                "verbose+"          => \$opt_verbose,           # flag, multiple use allowed
70
                "Output=s"          => \$opt_output,
71
                "GccPath=s"         => \$opt_gcc_path,
72
                "Arch=s"            => \$opt_arch,
73
                "Driver=s"          => \$opt_driver,
74
                "LeaveTmp:s"        => \$opt_leavetmp,
75
                "Verbose:s"         => \$opt_show_cmds,
76
                "Type=s"            => \$opt_type,
77
                "Platform=s"        => \$opt_platform,
78
                "Define=s"          => \@opt_defs,
79
                "Define=s"          => \@opt_defs,
80
                "Incdir=s"          => \@opt_incdirs,
81
                "LocalBinDir=s"     => \$opt_localbindir,
82
                "ExternalModule=s"  => \@opt_external_modules,
83
                "Clean"             => \$opt_clean,
227 dpurdie 84
                );
85
 
86
#
87
#   Process help and manual options
88
#
89
pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);
90
pod2usage(-verbose => 1) if ($opt_help == 2 );
91
pod2usage(-verbose => 2) if ($opt_manual || ($opt_help > 2));
92
#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ( $#ARGV >= 0 );
93
 
94
#
95
#   Sanity Test user input
96
#
97
Error ("No Output File specified") unless ( $opt_output );
98
 
99
#
100
#   Locate the Kernel Headers
101
#   This will be provided by one of the external packages
102
#   Paths to the packages will be in @opt_incdirs
103
#   Look for a dir ectory with a 'Makefile' - use the first one
104
#
105
my $KERNELDIR;
106
foreach  ( @opt_incdirs )
107
{
108
    my $test_dir = $_ . '/' . $opt_platform;
109
    next unless ( -d $test_dir );
110
    next unless ( -f $test_dir . '/Makefile' );
111
    $KERNELDIR = $test_dir;
112
}
113
Error ("Could not find the Kernel Headers",
114
       "Need a package that contains include/$opt_platform/Makefile"
115
      ) unless ( $KERNELDIR );
5672 dpurdie 116
#
117
#   Must have a nice name for the driver
118
#
119
Error ("No driver name specified") unless ( $opt_driver );
227 dpurdie 120
 
121
#
122
#   Calculate required bits
123
#   The generated file. Based on the name of the desired output file and the
124
#   source path.
125
#
126
my $gen_file = StripDir($opt_output);
5672 dpurdie 127
my $out_dir = StripFileExt($opt_output);
128
my $symdir = catdir($opt_localbindir, $opt_driver);
227 dpurdie 129
 
130
#
131
#   Cross-compiler toolchain root
132
#   Based on GccPath, remove the gcc bit
133
#
134
my $CROSS_COMPILE = $opt_gcc_path;
135
   $CROSS_COMPILE =~ s~-gcc$~-~;
136
 
137
#
138
#   The required architecture
139
#
140
my $ARCH;
141
   $ARCH = 'arm'  if ( $opt_arch =~ m/arm/i );
142
   $ARCH = 'i386' if ( $opt_arch =~ m/i386/i );
255 dpurdie 143
   $ARCH = 'powerpc' if ( $opt_arch =~ m/powerpc/i );
227 dpurdie 144
   Error ("Cannot determine architecture") unless ( $ARCH );
145
 
146
#
147
#   Source files
148
#   These may be comma seperated. Expand the array
149
#
150
@opt_source = @ARGV;
151
Error ("No source files specified" ) unless ( @opt_source );
152
 
153
#
5672 dpurdie 154
#   Locate required symvers files
227 dpurdie 155
#
5672 dpurdie 156
if (@opt_external_modules)
227 dpurdie 157
{
5672 dpurdie 158
    foreach my $emodule (@opt_external_modules)
159
    {
160
        my $mpath = catfile($opt_localbindir,$emodule,'Module.symvers');
161
        ReportError("External Module symbols not found for: " . $emodule) unless ((-f $mpath) || $opt_clean); 
162
        push @opt_external_modules_paths, $mpath;
163
    }
164
    ErrorDoExit() unless $opt_clean;
227 dpurdie 165
}
5672 dpurdie 166
 
167
unless ($opt_clean)
227 dpurdie 168
{
5672 dpurdie 169
    Message    "======================================================================";
170
    Message    "Build Linux Device Driver using the native build method";
171
    Message    "         Driver : $opt_driver";
172
    Message    "          Arch  : $ARCH";
173
    Message    "          Type  : $opt_type";
174
    Message    "         Output : $opt_output";
175
    Message    "       Platform : $opt_platform";
176
    Message    " Cross Compiler : $CROSS_COMPILE";
177
    Message    " Kernel Headers : $KERNELDIR";
178
    Message    "         Source : @opt_source";
179
    foreach  ( @opt_external_modules )
180
    {
181
        Message    "External Module : $_";
182
    }
183
    foreach  ( @opt_defs )
184
    {
185
        Message    "         Define : $_";
186
    }
187
    foreach  ( @opt_incdirs )
188
    {
189
        Message    "         Incdir : $_";
190
    }
191
 
192
    Message    "======================================================================";
227 dpurdie 193
}
194
 
381 dpurdie 195
#
196
#   Convert the list of source files into object files
197
#   Needed for cleaning
198
#
199
my @obj_files = map { $_ =~ s~\.\w+$~.o~; $_ } @opt_source;
227 dpurdie 200
 
201
#
202
#   Clean any existing build artifacts
381 dpurdie 203
#   The build options to place things in a different diractory are broken.
227 dpurdie 204
#   We must be able to build for multiple targets without confusion so we
205
#   clean, then build, then copy out the bits we need.
5672 dpurdie 206
cleanAll();
207
exit if $opt_clean;
227 dpurdie 208
 
209
#
210
#   Generate a Makefile for use by the driver Builder
211
#   This encapsulates the complete driver build mechanism
212
#
213
create_makefile();
214
 
215
#
216
#   Remove some 'make' environment variables
217
#   The JATS make and the PACKAGE make must not know about each other
218
#
369 dpurdie 219
foreach my $var (qw ( MAKE MAKEFLAGS MAKEOVERRIDES MAKELEVEL MAKE_MODE
255 dpurdie 220
                     CC CXX CPP EXTRA_CFLAGS CFLAGS ASFLAGS LDFLAGS
227 dpurdie 221
                     DEBFLAGS LDDINC DEBUG KERNELRELEASE LDDINC
369 dpurdie 222
                     ))
227 dpurdie 223
{
224
    delete $ENV{$var};
225
}
226
 
227
#
228
#   Build up the make command
229
#   Create an array of arguments - Don't need to escape funny bits
230
#
231
my @make_args = ();
232
push @make_args, "ARCH=$ARCH";
233
push @make_args, "CROSS_COMPILE=$CROSS_COMPILE";
234
push @make_args, "KERNELDIR=$KERNELDIR";
235
push @make_args, "-f", "Kbuild";
236
push @make_args, "V=1" unless ( $opt_show_cmds );
237
 
238
System ( 'make', @make_args );
239
 
240
Error  ("Generated output module file not found: $gen_file") unless ( -f $gen_file );
241
copy ( $gen_file, $opt_output ) || Error ("Cannot copy output file: $opt_output");
5672 dpurdie 242
 
243
#
244
#   Copy Module.symvers into a local directory for inter-module building
245
#   So far this is only supported within the same build - ie: Module.symvers
246
#   must be created in this build. The file will not be sourced from a package.
247
#   #
248
my $symfile = 'Module.symvers';
249
if ( -f $symfile && -s $symfile  )
250
{
251
    mkpath ($symdir) || Error ("Can't create $symdir", $!); 
252
    copy ( $symfile, $out_dir ) || Error ("Cannot copy $symfile to $out_dir");
253
    copy ( $symfile, $symdir ) || Error ("Cannot copy $symfile to $symdir");
254
}
227 dpurdie 255
clean() unless $opt_leavetmp;
256
 
257
Message "Script complete";
258
exit 0;
259
 
260
#-------------------------------------------------------------------------------
261
# Function        : create_makefile
262
#
263
# Description     : Generate a makefile called Kbuild
264
#                   This will be used by the kernel builder to do the hard work
265
#
266
#                   The makefile is created via a template embedded in this file
267
#
268
# Inputs          : None
269
#
270
# Returns         : Creates a file called Kbuild
271
#
272
sub create_makefile
273
{
274
    #
275
    #   Create variables for the data that will be substituted
276
    #
277
    my $driver_line = "obj-m	:= $opt_driver.o";
278
 
279
    my $file_list = "${opt_driver}-objs := @obj_files";
280
    my $debug_line = "DEBUG = y";
281
       $debug_line = "# " . $debug_line unless ( $opt_type eq 'D' );
282
 
283
 
284
    my $filename = "Kbuild";
285
    unlink ($filename);
286
    open (KBUILD, ">", $filename ) || Error ("Cannot generate file: $filename");
287
    while ( <DATA> )
288
    {
289
        $_ =~ s~\s+$~~;
290
 
291
        #
292
        #   Replace the entire line
293
        #
294
        $_ = $debug_line if ( m~__DEBUG_LINE__~ );
295
        $_ = $driver_line if ( m~__DEVICE_NAME__~ );
296
        $_ = $file_list if ( m~__FILE_LIST__~ );
297
        last if ( m~__END__~ );
298
 
299
        if ( m~__DEFINES__~ )
300
        {
301
            print KBUILD "# User definitions\n";
302
            foreach my $line ( @opt_defs )
303
            {
255 dpurdie 304
                print KBUILD "EXTRA_CFLAGS += -D$line\n";
227 dpurdie 305
            }
306
            print KBUILD "# End of User definitions\n";
307
            next;
308
        }
309
 
5672 dpurdie 310
        if ( m~__EXTERNAL_MODULES__~ )
311
        {
312
            print KBUILD "# Start of KBUILD_EXTRA_SYMBOLS\n";
313
            foreach my $line ( @opt_external_modules_paths )
314
            {
315
                if ( -s $line)
316
                {
317
                    print KBUILD "KBUILD_EXTRA_SYMBOLS += \$(PWD)/$line\n";
318
                }
319
            }
320
            print KBUILD "# End of KBUILD_EXTRA_SYMBOLS\n";
321
            next;
322
        }
323
 
227 dpurdie 324
        if ( m~__INCDIR__~ )
325
        {
326
            print KBUILD "# Search Include Directories\n";
327
            foreach my $line ( @opt_incdirs )
328
            {
329
                if ( ! -d $line )
330
                {
331
                    Verbose("Incdir does not exist: $line");
332
                    next;
333
                }
334
 
335
                if ( $line =~ m~^/~ )
336
                {
255 dpurdie 337
                    print KBUILD "EXTRA_CFLAGS += -I$line\n";
227 dpurdie 338
                }
339
                else
340
                {
255 dpurdie 341
                    print KBUILD "EXTRA_CFLAGS += -I\$(PWD)/$line\n";
227 dpurdie 342
                }
343
            }
344
            print KBUILD "# End of User Include Directories\n";
345
            next;
346
        }
347
 
348
 
349
        print KBUILD "$_\n";
350
    }
351
 
352
    close (KBUILD);
353
 
354
}
355
 
356
#-------------------------------------------------------------------------------
357
# Function        : clean
358
#
359
# Description     : Clean up build artifacts
381 dpurdie 360
#                   Need to remove stuff that we build as the the kernel builder
361
#                   doesn't handle multiple platforms
227 dpurdie 362
#
381 dpurdie 363
# Inputs          : Globals: @obj_files
227 dpurdie 364
#
381 dpurdie 365
# Returns         : Nothing
227 dpurdie 366
#
367
sub clean
368
{
5672 dpurdie 369
    foreach my $files (qw (*.o *~ core .depend .*.cmd *.ko *.mod.c Kbuild Module.symvers Module.markers modules.order ), @obj_files )
227 dpurdie 370
    {
371
        unlink ( glob ( $files ));
372
    }
373
    rmtree  ( '.tmp_versions' );
374
}
375
 
5672 dpurdie 376
#-------------------------------------------------------------------------------
377
# Function        : cleanAll
378
#
379
# Description     : Clobber all build artifacts
380
#
381
# Inputs          : Globals: @obj_files
382
#
383
# Returns         : Nothing
384
#
385
sub cleanAll
386
{
387
    clean();
388
    rmtree  ( $symdir );
389
}
390
 
391
 
227 dpurdie 392
__DATA__
393
#
394
#   This is a generated file
395
#   Do not edit or check into version control
396
################################################################################
397
 
398
# Comment/uncomment the following line to disable/enable debugging
399
DEBUG = y __DEBUG_LINE__
400
 
401
__DEFINES__
402
 
5672 dpurdie 403
__EXTERNAL_MODULES__
404
 
227 dpurdie 405
__INCDIR__
406
 
255 dpurdie 407
# Add your debugging flag (or not) to EXTRA_CFLAGS
227 dpurdie 408
ifeq ($(DEBUG),y)
409
  DEBFLAGS = -O -g -DDEV_DEBUG # "-O" is needed to expand inlines
410
else
411
  DEBFLAGS = -O2
412
endif
413
 
255 dpurdie 414
EXTRA_CFLAGS += $(DEBFLAGS)
415
EXTRA_CFLAGS += -I$(LDDINC)
227 dpurdie 416
 
417
ifneq ($(KERNELRELEASE),)
418
# call from kernel build system
419
 
420
llcd-objs := __FILE_LIST__
421
obj-m	:= __DEVICE_NAME__
422
 
423
else
424
 
425
KERNELDIR ?= "-- Must be defined by calling makefile"
426
PWD       := $(shell pwd)
427
 
428
modules:
429
	$(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules
430
 
431
endif
432
 
433
depend .depend dep:
255 dpurdie 434
	$(CC) $(EXTRA_CFLAGS) -M *.c > .depend
227 dpurdie 435
 
436
 
437
ifeq (.depend,$(wildcard .depend))
438
include .depend
439
endif
440
 
441
__END__
442
 
443
#-------------------------------------------------------------------------------
444
#   Documentation
445
#
446
 
447
=pod
448
 
361 dpurdie 449
=for htmltoc    MAKEUTIL::
450
 
227 dpurdie 451
=head1 NAME
452
 
453
jats_buildlinux - Build a Linux Device Driver
454
 
455
=head1 SYNOPSIS
456
 
457
perl jats_buildlinux [options] source_files+
458
 
5672 dpurdie 459
 Options:               
460
    -help                 - brief help message
461
    -help -help           - Detailed help message
462
    -man                  - Full documentation
463
    -Output=path          - Path to the output file
464
    -Kernel=path          - Path to the Kernel Headers
465
    -GccPath=path         - Path to the gcc compiler to use
466
    -Arch=name            - Architecture name
467
    -Driver=name          - Base name of the driver to build
468
    -LeaveTmp=num         - Leave tmp files after build
469
    -Verbose=num          - Verbose command output
470
    -Type=[P|D]           - Type of build
471
    -Platform=name        - Target Platform
472
    -Define=text          - Definitions to pass to compiler
473
    -Incdir=path          - Extend the header file search path
474
    -LocalBinDir=path     - Path to store Module.symvers
475
    -ExternalModule=name  - Name of an external module
476
    -Clean                - Clean up generated files
227 dpurdie 477
 
478
=head1 OPTIONS
479
 
480
=over 8
481
 
482
=item B<-help>
483
 
484
Print a brief help message and exits.
485
 
486
=item B<-help -help>
487
 
488
Print a detailed help message with an explanation for each option.
489
 
490
=item B<-man>
491
 
492
Prints the manual page and exits.
493
 
361 dpurdie 494
=back
227 dpurdie 495
 
496
=head1 DESCRIPTION
497
 
498
This program is used internally by Jats to implement the body of the MakeLinuxDriver
499
directive. The command is not intended to be called by the user.
500
 
501
=head1 EXAMPLE
502
 
503
    MakeLinuxDriver ('*', 'llcd.ko',
504
                          '--KernelPackage=linux_kernel_headers', @CSRCS );
505
 
506
 
507
=cut
508