41 | Optional rules can be helpful for rules (often autogenerated) that 42 | might be slow or require dependencies that not all users will 43 | have. They can be convenient for scripts that define a whole slew 44 | of rules in a facfile, and which don't want to determine which of 45 | these are needed for the actual build. Or for something like 46 | documentation, which only some users will want to actually build. 47 |
48 | 49 | 3. Output specifications beginning with `"> "` followed by the name of 50 | the file that is output. There is no escaping performed, and only 51 | newlines and null characters are disallowed in the file name. 52 | There is little need to specify the output for rules, since fac 53 | can determine this automatically. The only reason to specify 54 | output is so that on the very first build a user can request that 55 | we build only the specified rule. 56 | 57 | 4. Input specifications beginning with `"< "` followed by the name of 58 | the file that is required. You only need specify inputs when they 59 | are generated files. Even then, you need only specify the inputs 60 | if you wish to have the build succeed on the first attempt. 61 | 62 | 5. Dependency output specifications beginning with `"M "` followed by 63 | the name of the deps file that is generated by the command. This 64 | is designed for compilers which have the ability to track 65 | dependencies and output a `Makefile` fragment documenting those 66 | dependencies. This is implemented for two reasons. Firstly, by 67 | relying on the compiler for dependency tracking, fac can run more 68 | quickly than if it tracks file accesses itself. Secondly, it makes 69 | fac more useful on platforms (currently Windows and Mac OS) where 70 | it is unable to track dependencies. *This feature is only 71 | available in the version of fac implemented in rust.* 72 | 73 | 6. There are two ways to specify "cache" files. A cache file is a 74 | file that may be either read or written by a given command, but 75 | doesn't affect the output and not itself an output. One nice 76 | example is the ".pyc" files sometimes generated when you run a 77 | python program. One python command may produce a .pyc file, and 78 | another may read it (if they both use the same module), but that 79 | does not mean that there is a dependency between those two 80 | commands. You can specify a cache suffix (such as `.pyc`) using a 81 | `"c "` line, or you can specify a cache prefix (such as 82 | `~/.ccache`) using a capitalized `"C "` line. The latter can be 83 | helpful if you find that your software is being rebuilt needlessly 84 | due to some cache file being modified. 85 | -------------------------------------------------------------------------------- /bench/hierarchy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os, hashlib, time, numpy, sys, datetime 4 | 5 | name = 'hierarchy' 6 | 7 | def make_name(i): 8 | path = '.' 9 | digits = '%d' % i 10 | for d in digits: 11 | path = path+'/number-'+d 12 | return path[2:]+('_%d' % i) 13 | 14 | allowed_chars = 'abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ' 15 | 16 | def hashid(n): 17 | m = hashlib.sha1() 18 | m.update(str(n).encode('utf-8')) 19 | name = '' 20 | for i in m.digest()[:24]: 21 | name += allowed_chars[i % len(allowed_chars)] 22 | return name+('_%d' % n) 23 | 24 | def hash_integer(n): 25 | m = hashlib.sha1() 26 | m.update(str(n).encode('utf-8')) 27 | name = 0 28 | for i in m.digest()[:8]: 29 | name = name*256 + i 30 | return abs(name) 31 | 32 | def open_and_gitadd(fname): 33 | f = open(fname, 'w') 34 | assert(not os.system('git add '+fname)) 35 | return f 36 | 37 | def create_bench(N): 38 | sconsf = open_and_gitadd('SConstruct') 39 | facf = open_and_gitadd('top.fac') 40 | open_and_gitadd('Tupfile.ini') 41 | sconsf.write(""" 42 | env = Environment(CPPPATH=['.']) 43 | """) 44 | for i in range(N): 45 | if i > 9: 46 | os.makedirs(os.path.dirname(make_name(i)), exist_ok=True) 47 | cname = make_name(i) + '.c' 48 | hname = make_name(i) + '.h' 49 | includes = '' 50 | funcs = '' 51 | for xx in [i+ii for ii in range(10)]: 52 | nhere = hash_integer(xx) % N 53 | includes += '#include "%s.h"\n' % make_name(nhere) 54 | funcs += ' %s();\n' % hashid(nhere) 55 | facf.write(""" 56 | # %d 57 | | gcc -I. -O2 -c -o %s.o %s.c 58 | > %s.o 59 | """ % (i, make_name(i), make_name(i), make_name(i))) 60 | sconsf.write(""" 61 | env.Object('%s.c') 62 | """ % make_name(i)) 63 | f = open_and_gitadd(make_name(i)+'.c') 64 | f.write('\n') 65 | f.write("""/* c file %s */ 66 | 67 | %s#include "%s" 68 | 69 | #include