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-10-18 02:49:24 +04:00
* every file in the kernel includes autoconf . h .
2005-04-17 02:20:36 +04:00
*
2009-10-18 02:49:24 +04:00
* If the user re - runs make * config , autoconf . h will be
2005-04-17 02:20:36 +04:00
* 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
2009-10-18 02:49:24 +04:00
* the dependency on autoconf . h by a dependency on every config
2005-04-17 02:20:36 +04:00
* 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
2009-10-18 02:49:24 +04:00
* process filtering out the dependency on autoconf . h and adding
2005-04-17 02:20:36 +04:00
* 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
}
2010-11-09 18:29:27 +03:00
struct item {
struct item * next ;
unsigned int len ;
unsigned int hash ;
char name [ 0 ] ;
} ;
2005-04-17 02:20:36 +04:00
2010-11-09 18:29:27 +03:00
# define HASHSZ 256
static struct item * hashtab [ HASHSZ ] ;
2005-04-17 02:20:36 +04:00
2010-11-09 18:29:27 +03:00
static unsigned int strhash ( const char * str , unsigned int sz )
{
/* fnv32 hash */
unsigned int i , hash = 2166136261U ;
2005-04-17 02:20:36 +04:00
2010-11-09 18:29:27 +03:00
for ( i = 0 ; i < sz ; i + + )
hash = ( hash ^ str [ i ] ) * 0x01000193 ;
return hash ;
}
2005-04-17 02:20:36 +04:00
/*
* Lookup a value in the configuration string .
*/
2010-11-09 18:29:27 +03:00
static int is_defined_config ( const char * name , int len , unsigned int hash )
2005-04-17 02:20:36 +04:00
{
2010-11-09 18:29:27 +03:00
struct item * aux ;
for ( aux = hashtab [ hash % HASHSZ ] ; aux ; aux = aux - > next ) {
if ( aux - > hash = = hash & & aux - > len = = len & &
memcmp ( aux - > name , name , len ) = = 0 )
2005-04-17 02:20:36 +04:00
return 1 ;
}
return 0 ;
}
/*
* Add a new value to the configuration string .
*/
2010-11-09 18:29:27 +03:00
static void define_config ( const char * name , int len , unsigned int hash )
2005-04-17 02:20:36 +04:00
{
2010-11-09 18:29:27 +03:00
struct item * aux = malloc ( sizeof ( * aux ) + len ) ;
2005-04-17 02:20:36 +04:00
2010-11-09 18:29:27 +03:00
if ( ! aux ) {
perror ( " fixdep:malloc " ) ;
exit ( 1 ) ;
}
memcpy ( aux - > name , name , len ) ;
aux - > len = len ;
aux - > hash = hash ;
aux - > next = hashtab [ hash % HASHSZ ] ;
hashtab [ hash % HASHSZ ] = aux ;
2005-04-17 02:20:36 +04:00
}
/*
* 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
{
2010-11-09 18:29:27 +03:00
struct item * aux , * next ;
unsigned int i ;
for ( i = 0 ; i < HASHSZ ; i + + ) {
for ( aux = hashtab [ i ] ; aux ; aux = next ) {
next = aux - > next ;
free ( aux ) ;
}
hashtab [ i ] = NULL ;
}
2005-04-17 02:20:36 +04:00
}
/*
* Record the use of a CONFIG_ * word .
*/
2010-11-09 18:29:27 +03:00
static void use_config ( const char * m , int slen )
2005-04-17 02:20:36 +04:00
{
2010-11-09 18:29:27 +03:00
unsigned int hash = strhash ( m , slen ) ;
int c , i ;
2005-04-17 02:20:36 +04:00
2010-11-09 18:29:27 +03:00
if ( is_defined_config ( m , slen , hash ) )
2005-04-17 02:20:36 +04:00
return ;
2010-11-09 18:29:27 +03:00
define_config ( m , slen , hash ) ;
2005-04-17 02:20:36 +04:00
2010-11-09 18:29:27 +03:00
printf ( " $(wildcard include/config/ " ) ;
for ( i = 0 ; i < slen ; i + + ) {
c = m [ i ] ;
if ( c = = ' _ ' )
c = ' / ' ;
2005-04-17 02:20:36 +04:00
else
2010-11-09 18:29:27 +03:00
c = tolower ( c ) ;
putchar ( c ) ;
2005-04-17 02:20:36 +04:00
}
2010-11-09 18:29:27 +03:00
printf ( " .h) \\ \n " ) ;
2005-04-17 02:20:36 +04:00
}
2010-11-09 18:29:27 +03:00
static void parse_config_file ( const char * map , size_t len )
2005-04-17 02:20:36 +04:00
{
2010-11-09 18:29:27 +03:00
const int * end = ( const int * ) ( map + len ) ;
2005-04-17 02:20:36 +04:00
/* start at +1, so that p can never be < map */
2010-11-09 18:29:27 +03:00
const int * m = ( const int * ) map + 1 ;
const 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 ) ;
}
2010-11-09 18:29:27 +03:00
static void do_config_file ( const 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 ;
2009-10-18 02:49:24 +04:00
if ( strrcmp ( s , " include/generated/autoconf.h " ) & &
2005-04-17 02:20:36 +04:00
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 ;
}