1

I have recently converted my works make based build system to shake. I am now trying to make shake a little more robust to changes in the directory structure so that I do not have to regenerate the build system.

Each of my projects use are C based and have the following directory structure

  • src
    • source folder 1
    • source folder 2
  • inc
    • inc folder 1
    • inc folder 2

I am able to capture all the source files but what I cant get to work is capturing the include folders. The root inc folder and the sub folders I am trying to capture into a variable in the build system. I have been using the following setup

includes = getDirectoryDir "inc"

This will give me the included sub folders but not the root folder inc. Which I thought I could work around but inc will not be tracked.

What I would like is to have something like

includes = getDirectoryDirAndRoot "inc"

Which will capture each of the subdirectories and the root directory and have them tracked in the build system.

That aside what I have also tried to use

gcc -o out includes

But I would need to have every element in includes prepended with "-I" which I can't seem to figure out.

I guess how would one go abut doing this in shake, in make I can accomplish all of this by using makes shell function and a couple of string manipulation functions.

2 Answers2

0

Have a look at addOracle and its cousin addOracleCache. This should allow you to depend on information besides the files themselves, such as directories to be included.

But I would need to have every element in includes prepended with "-I" which I can't seem to figure out.

You can use Haskell here. If you have a list of directories directories :: [FilePath], you can turn those into compiler flags with

asIncludes :: [FilePath] -> [String]
asIncludes = fmap ("I" ++)
0

I think the question can be interpreted both ways, and both ways are useful (you may even want both), so I'll give two answers:

Answer 1: You want the C file to be recompiled if any file in the inc directory changes.

"*.c" *> \out -> do headerFiles <- getDirectoryFiles "inc" "**/*.h" need headerFiles ...

This snippet gets a list of all header files in the inc directory (or it's subdirectories) and introduces a dependency on them. If any header file changes, this rule will rerun.

Answer 2: You want to get the list of directories to pass to gcc.

"*.c" *> \out -> do includeDirs <- getDirectoryDirs "inc" cmd "gcc -c" [out] "-Iinc" (map ("-Iinc/" ++) includeDirs) ...

This snippet gets the directory names under inc and then uses map to prepend -Iinc/ over them. It also passes -Iinc directly. If the list of directories under inc changes this rule will rebuild. However, if the header files contained in those directories change nothing will rebuild. You can add dependencies on the used header files with the gcc -MD family of flags, as described in the Shake user manual, or using the technique from Answer 1.

Neil Mitchell
  • 9,090
  • 1
  • 27
  • 85