2005-04-17 02:20:36 +04:00
/*
* " Optimize " a list of dependencies as spit out by gcc - MD
* for the kernel build
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*
* Author Kai Germaschewski
* Copyright 2002 by Kai Germaschewski < kai . germaschewski @ gmx . de >
*
* This software may be used and distributed according to the terms
* of the GNU General Public License , incorporated herein by reference .
*
*
* Introduction :
*
* gcc produces a very nice and correct list of dependencies which
* tells make when to remake a file .
*
* To use this list as - is however has the drawback that virtually
2009-06-12 03:02:35 +04:00
* every file in the kernel includes < linux / autoconf . h > .
2005-04-17 02:20:36 +04:00
*
* If the user re - runs make * config , linux / autoconf . h will be
* regenerated . make notices that and will rebuild every file which
* includes autoconf . h , i . e . basically all files . This is extremely
* annoying if the user just changed CONFIG_HIS_DRIVER from n to m .
*
* So we play the same trick that " mkdep " played before . We replace
* the dependency on linux / autoconf . h by a dependency on every config
* option which is mentioned in any of the listed prequisites .
*
2007-03-29 13:27:14 +04:00
* kconfig populates a tree in include / config / with an empty file
* for each config symbol and when the configuration is updated
* the files representing changed config options are touched
* which then let make pick up the changes and the files that use
* the config symbols are rebuilt .
2005-04-17 02:20:36 +04:00
*
* So if the user changes his CONFIG_HIS_DRIVER option , only the objects
* which depend on " include/linux/config/his/driver.h " will be rebuilt ,
* so most likely only his driver ; - )
*
* The idea above dates , by the way , back to Michael E Chastain , AFAIK .
*
* So to get dependencies right , there are two issues :
* o if any of the files the compiler read changed , we need to rebuild
* o if the command line given to the compile the file changed , we
* better rebuild as well .
*
* The former is handled by using the - MD output , the later by saving
* the command line used to compile the old object and comparing it
* to the one we would now use .
*
* Again , also this idea is pretty old and has been discussed on
* kbuild - devel a long time ago . I don ' t have a sensibly working
* internet connection right now , so I rather don ' t mention names
* without double checking .
*
* This code here has been based partially based on mkdep . c , which
* says the following about its history :
*
* Copyright abandoned , Michael Chastain , < mailto : mec @ shout . net > .
* This is a C version of syncdep . pl by Werner Almesberger .
*
*
* It is invoked as
*
* fixdep < depfile > < target > < cmdline >
*
* and will read the dependency file < depfile >
*
* The transformed dependency snipped is written to stdout .
*
* It first generates a line
*
* cmd_ < target > = < cmdline >
*
* and then basically copies the . < target > . d file to stdout , in the
* process filtering out the dependency on linux / autoconf . h and adding
* dependencies on include / config / my / option . h for every
* CONFIG_MY_OPTION encountered in any of the prequisites .
*
* It will also filter out all the dependencies on * . ver . We need
* to make sure that the generated version checksum are globally up
* to date before even starting the recursive build , so it ' s too late
* at this point anyway .
*
* The algorithm to grep for " CONFIG_... " is bit unusual , but should
* be fast ; - ) We don ' t even try to really parse the header files , but
* merely grep , i . e . if CONFIG_FOO is mentioned in a comment , it will
* be picked up as well . It ' s not a problem with respect to
* correctness , since that can only give too many dependencies , thus
* we cannot miss a rebuild . Since people tend to not mention totally
* unrelated CONFIG_ options all over the place , it ' s not an
* efficiency problem either .
*
* ( Note : it ' d be easy to port over the complete mkdep state machine ,
* but I don ' t think the added complexity is worth it )
*/
/*
* Note 2 : if somebody writes HELLO_CONFIG_BOOM in a file , it will depend onto
* CONFIG_BOOM . This could seem a bug ( not too hard to fix ) , but please do not
* fix it ! Some UserModeLinux files ( look at arch / um / ) call CONFIG_BOOM as
* UML_CONFIG_BOOM , to avoid conflicts with / usr / include / linux / autoconf . h ,
* through arch / um / include / uml - config . h ; this fixdep " bug " makes sure that
* those files will have correct dependencies .
*/
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/mman.h>
# include <unistd.h>
# include <fcntl.h>
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <limits.h>
# include <ctype.h>
# include <arpa/inet.h>
# define INT_CONF ntohl(0x434f4e46)
# define INT_ONFI ntohl(0x4f4e4649)
# define INT_NFIG ntohl(0x4e464947)
# define INT_FIG_ ntohl(0x4649475f)
char * target ;
char * depfile ;
char * cmdline ;
2009-09-18 23:49:23 +04:00
static void usage ( void )
2005-04-17 02:20:36 +04:00
{
fprintf ( stderr , " Usage: fixdep <depfile> <target> <cmdline> \n " ) ;
exit ( 1 ) ;
}
2005-12-26 01:21:14 +03:00
/*
* Print out the commandline prefixed with cmd_ < target filename > : =
2006-01-30 12:04:27 +03:00
*/
2009-09-18 23:49:23 +04:00
static void print_cmdline ( void )
2005-04-17 02:20:36 +04:00
{
2006-01-30 12:04:27 +03:00
printf ( " cmd_%s := %s \n \n " , target , cmdline ) ;
2005-04-17 02:20:36 +04:00
}
char * str_config = NULL ;
int size_config = 0 ;
int len_config = 0 ;
/*
* Grow the configuration string to a desired length .
* Usually the first growth is plenty .
*/
2009-09-18 23:49:23 +04:00
static void grow_config ( int len )
2005-04-17 02:20:36 +04:00
{
while ( len_config + len > size_config ) {
if ( size_config = = 0 )
size_config = 2048 ;
str_config = realloc ( str_config , size_config * = 2 ) ;
if ( str_config = = NULL )
{ perror ( " fixdep:malloc " ) ; exit ( 1 ) ; }
}
}
/*
* Lookup a value in the configuration string .
*/
2009-09-18 23:49:23 +04:00
static int is_defined_config ( const char * name , int len )
2005-04-17 02:20:36 +04:00
{
const char * pconfig ;
const char * plast = str_config + len_config - len ;
for ( pconfig = str_config + 1 ; pconfig < plast ; pconfig + + ) {
if ( pconfig [ - 1 ] = = ' \n '
& & pconfig [ len ] = = ' \n '
& & ! memcmp ( pconfig , name , len ) )
return 1 ;
}
return 0 ;
}
/*
* Add a new value to the configuration string .
*/
2009-09-18 23:49:23 +04:00
static void define_config ( const char * name , int len )
2005-04-17 02:20:36 +04:00
{
grow_config ( len + 1 ) ;
memcpy ( str_config + len_config , name , len ) ;
len_config + = len ;
str_config [ len_config + + ] = ' \n ' ;
}
/*
* Clear the set of configuration strings .
*/
2009-09-18 23:49:23 +04:00
static void clear_config ( void )
2005-04-17 02:20:36 +04:00
{
len_config = 0 ;
define_config ( " " , 0 ) ;
}
/*
* Record the use of a CONFIG_ * word .
*/
2009-09-18 23:49:23 +04:00
static void use_config ( char * m , int slen )
2005-04-17 02:20:36 +04:00
{
char s [ PATH_MAX ] ;
char * p ;
if ( is_defined_config ( m , slen ) )
return ;
define_config ( m , slen ) ;
memcpy ( s , m , slen ) ; s [ slen ] = 0 ;
for ( p = s ; p < s + slen ; p + + ) {
if ( * p = = ' _ ' )
* p = ' / ' ;
else
2005-06-26 01:59:22 +04:00
* p = tolower ( ( int ) * p ) ;
2005-04-17 02:20:36 +04:00
}
printf ( " $(wildcard include/config/%s.h) \\ \n " , s ) ;
}
2009-09-18 23:49:23 +04:00
static void parse_config_file ( char * map , size_t len )
2005-04-17 02:20:36 +04:00
{
int * end = ( int * ) ( map + len ) ;
/* start at +1, so that p can never be < map */
int * m = ( int * ) map + 1 ;
2005-06-26 01:59:22 +04:00
char * p , * q ;
2005-04-17 02:20:36 +04:00
for ( ; m < end ; m + + ) {
2005-06-26 01:59:22 +04:00
if ( * m = = INT_CONF ) { p = ( char * ) m ; goto conf ; }
if ( * m = = INT_ONFI ) { p = ( char * ) m - 1 ; goto conf ; }
if ( * m = = INT_NFIG ) { p = ( char * ) m - 2 ; goto conf ; }
if ( * m = = INT_FIG_ ) { p = ( char * ) m - 3 ; goto conf ; }
2005-04-17 02:20:36 +04:00
continue ;
conf :
if ( p > map + len - 7 )
continue ;
if ( memcmp ( p , " CONFIG_ " , 7 ) )
continue ;
for ( q = p + 7 ; q < map + len ; q + + ) {
if ( ! ( isalnum ( * q ) | | * q = = ' _ ' ) )
goto found ;
}
continue ;
found :
2007-03-29 13:27:14 +04:00
if ( ! memcmp ( q - 7 , " _MODULE " , 7 ) )
q - = 7 ;
2007-05-02 15:49:06 +04:00
if ( ( q - p - 7 ) < 0 )
continue ;
2005-04-17 02:20:36 +04:00
use_config ( p + 7 , q - p - 7 ) ;
}
}
/* test is s ends in sub */
2009-09-18 23:49:23 +04:00
static int strrcmp ( char * s , char * sub )
2005-04-17 02:20:36 +04:00
{
int slen = strlen ( s ) ;
int sublen = strlen ( sub ) ;
if ( sublen > slen )
return 1 ;
return memcmp ( s + slen - sublen , sub , sublen ) ;
}
2009-09-18 23:49:23 +04:00
static void do_config_file ( char * filename )
2005-04-17 02:20:36 +04:00
{
struct stat st ;
int fd ;
void * map ;
fd = open ( filename , O_RDONLY ) ;
if ( fd < 0 ) {
fprintf ( stderr , " fixdep: " ) ;
perror ( filename ) ;
exit ( 2 ) ;
}
fstat ( fd , & st ) ;
if ( st . st_size = = 0 ) {
close ( fd ) ;
return ;
}
map = mmap ( NULL , st . st_size , PROT_READ , MAP_PRIVATE , fd , 0 ) ;
if ( ( long ) map = = - 1 ) {
perror ( " fixdep: mmap " ) ;
close ( fd ) ;
return ;
}
parse_config_file ( map , st . st_size ) ;
munmap ( map , st . st_size ) ;
close ( fd ) ;
}
2009-09-18 23:49:23 +04:00
static void parse_dep_file ( void * map , size_t len )
2005-04-17 02:20:36 +04:00
{
2005-06-26 01:59:22 +04:00
char * m = map ;
char * end = m + len ;
char * p ;
2005-04-17 02:20:36 +04:00
char s [ PATH_MAX ] ;
p = strchr ( m , ' : ' ) ;
if ( ! p ) {
fprintf ( stderr , " fixdep: parse error \n " ) ;
exit ( 1 ) ;
}
memcpy ( s , m , p - m ) ; s [ p - m ] = 0 ;
printf ( " deps_%s := \\ \n " , target ) ;
m = p + 1 ;
clear_config ( ) ;
while ( m < end ) {
while ( m < end & & ( * m = = ' ' | | * m = = ' \\ ' | | * m = = ' \n ' ) )
m + + ;
p = m ;
while ( p < end & & * p ! = ' ' ) p + + ;
if ( p = = end ) {
do p - - ; while ( ! isalnum ( * p ) ) ;
p + + ;
}
memcpy ( s , m , p - m ) ; s [ p - m ] = 0 ;
if ( strrcmp ( s , " include/linux/autoconf.h " ) & &
strrcmp ( s , " arch/um/include/uml-config.h " ) & &
strrcmp ( s , " .ver " ) ) {
printf ( " %s \\ \n " , s ) ;
do_config_file ( s ) ;
}
m = p + 1 ;
}
printf ( " \n %s: $(deps_%s) \n \n " , target , target ) ;
printf ( " $(deps_%s): \n " , target ) ;
}
2009-09-18 23:49:23 +04:00
static void print_deps ( void )
2005-04-17 02:20:36 +04:00
{
struct stat st ;
int fd ;
void * map ;
fd = open ( depfile , O_RDONLY ) ;
if ( fd < 0 ) {
fprintf ( stderr , " fixdep: " ) ;
perror ( depfile ) ;
exit ( 2 ) ;
}
fstat ( fd , & st ) ;
if ( st . st_size = = 0 ) {
fprintf ( stderr , " fixdep: %s is empty \n " , depfile ) ;
close ( fd ) ;
return ;
}
map = mmap ( NULL , st . st_size , PROT_READ , MAP_PRIVATE , fd , 0 ) ;
if ( ( long ) map = = - 1 ) {
perror ( " fixdep: mmap " ) ;
close ( fd ) ;
return ;
}
parse_dep_file ( map , st . st_size ) ;
munmap ( map , st . st_size ) ;
close ( fd ) ;
}
2009-09-18 23:49:23 +04:00
static void traps ( void )
2005-04-17 02:20:36 +04:00
{
static char test [ ] __attribute__ ( ( aligned ( sizeof ( int ) ) ) ) = " CONF " ;
2009-06-10 23:48:23 +04:00
int * p = ( int * ) test ;
2005-04-17 02:20:36 +04:00
2009-06-10 23:48:23 +04:00
if ( * p ! = INT_CONF ) {
2005-04-17 02:20:36 +04:00
fprintf ( stderr , " fixdep: sizeof(int) != 4 or wrong endianess? %#x \n " ,
2009-06-10 23:48:23 +04:00
* p ) ;
2005-04-17 02:20:36 +04:00
exit ( 2 ) ;
}
}
int main ( int argc , char * argv [ ] )
{
traps ( ) ;
if ( argc ! = 4 )
usage ( ) ;
depfile = argv [ 1 ] ;
target = argv [ 2 ] ;
cmdline = argv [ 3 ] ;
print_cmdline ( ) ;
print_deps ( ) ;
return 0 ;
}