def install_python(dir, sources): basedir = dir scons.Mkdir(basedir) for file in sources: pyc = basedir + '/' + os.path.splitext( os.path.basename(file))[0] + '.pyc' scons.Command(pyc, file, _python_compile)
def Flex(self, flex_file): """Runs flex to convert a .l file into .cpp and .h files. This has the same issues as Lemon when it comes to variant dirs and such - see the docs on that method.""" assert os.path.basename(flex_file) == flex_file src_file = os.path.join(self.cur_src_dir, flex_file) # Make a copy of the src and variant dirs so they get copied into the # closure below src_dir = self.cur_src_dir var_dir = self.cur_var_dir # name of the flex file without the ".l" flex_file_base = os.path.splitext(flex_file)[0] generated_cpp_file = os.path.join(self.cur_var_dir, flex_file_base + '.yy.cpp') generated_h_file = os.path.join(self.cur_var_dir, flex_file_base + '.yy.h') # Flex puts its output in it's current working directory. Thus we need # to change dirs before running it and change back after. We don't want # to do that unless we actually need to do the build so we use the # closure/command trick that's used in the Lemon rule above. Thus the # build process is: # 1) cd to variant_dir # 2) Run flex over the .l file in the source dir # 3) cd back to where we started def run_flex(target, source, env): start_dir = os.getcwd() os.chdir(var_dir) res = scons.Execute('flex ' + src_file, chdir=var_dir) if res != 0: scons.Exit(1) os.chdir(start_dir) scons.Command([generated_cpp_file, generated_h_file], src_file, run_flex) # Here we return a File node that points to the generated file as if it # were generated in the non-variant dir. This is because scons knows # it's a build output and so automatically appends the variant dir. return [ generated_cpp_file, ]
def Lemon(self, src): """Run lemon to compile a .y file into a .cc and a .h file. The genrated files have the same base name as src but end with .cc or .h. Args: src: the name of the source file. Assumed to be in the same directory as the SConscript file from which builder.Lemon() was called. Returns: scons node object for the .cc file generated. This can then be used as input to other build rules. This does not return the .h file as that is typically not used in build rules. The single file is returned in a list as that is scons convention. The output files will be put into a variant subdirectory (e.g. ./debug for a debug build). We could put the files into the same directory as the .y file but that clutters the directory. More importantly, lemon has some command line flags that allows us to build optimized parsers. We're not using the currently, but in the future the generated source for a release build might be different from the source generate for a debug build. """ assert os.path.basename(src) == src # We need a 3-step build process here: # 1) Lemon always puts the generated .c and .h file in the same # directory as the source so we first copy the source file into the # variant dir. # 2) Run lemon to generate the the .c and .h files # 3) rename the .c file to a .cc file so scons realizes it's C++ and # builds it with g++ instead of gcc. # However, we don't want to do any of these things unless the .y file # has changed. So we create a single command with a single dependancy. # Scons will then run our function only if necessary. src_path = os.path.join(self.cur_src_dir, src) var_path = os.path.join(self.cur_var_dir, src) variant_dir = os.path.join(os.path.dirname(src_path), self.build_dir) # The name of the source file without the ".y" src_base_filename = os.path.splitext(src)[0] # The path to the generated .c file generated_c_path = os.path.join(self.cur_var_dir, src_base_filename + '.c') # The path to the generated .h file generated_h_path = os.path.join(self.cur_var_dir, src_base_filename + '.h') # Where we should copy the .c file to get a .cc file. desired_cc_path = os.path.join(self.cur_var_dir, src_base_filename + '.cc') # Copy self.cur_var_dir, which may refer to a different string by the # time run_lemon gets invoked by scons, into a new varible so it gets # copy into the run_lemon closure var_dir = self.cur_var_dir # Closure that will be run to generate the .cc and .h files if # necessary def run_lemon(target, source, env): """The targets, source, and environment are passed by scons but we can ignore them as we don't need them.""" # Copy the .y file into the variant dir shutil.copy(src_path, var_dir) ret = scons.Execute('lemon ' + var_path) if ret != 0: scons.Exit(1) # now rename the .c file to a .cc file shutil.move(generated_c_path, desired_cc_path) # This command indicates that the .cc and .h files are generated from # the .y file by running run_lemon. Scons will then call that function # if and only if the .y file has changed. res = scons.Command([desired_cc_path, generated_h_path], src_path, run_lemon) return [ desired_cc_path, ]