Till now i had the following code:
shakeArgsWith opts additionalFlags $ \flags targets -> return $ Just $ do
...
-- Get target arch from command line flags
let givenArch = listToMaybe [v | AFlag v <- flags]
let arch = fromMaybe defArch givenArch
...
-- Set the main target
let outName = masterOutName projType toolchain projName
let mainTgt = (case projType of
Binary _ -> "bin"
Archive -> "lib")
</> prettyShowArch arch
</> show variant
</> outName
-- Set the build directory for the current run
let buildDir = bldDir </> show toolchain </> prettyShowArch arch </> show variant
...
mainTgt %> \out -> do ...
...
buildDir <//> "*.o" %> \out -> do ...
...
Meaning that the names of the rules where constructed according to a command line flag that i was parsing (they contained the arch variable).
So if i gave shake --arch=x64
i was building the main target in bin/x64/Release
directory and my intermidiate build files in the tmp/x64/Release
folder accordingly.
But now instead of using the command line flag, i want the shared arch variable that is used to construct the rule names to be populated according to the output of some command, for example if i could define some top level action it would be this:
Stdout sout <- quietly $ cmd (EchoStdout False) (EchoStderr False) "gcc -dumpmachine" :: Action (Stdout String)
let foundArch = show (gccTripletToArch sout)
and use the variable foundArch instead of the arch when constructing the mainTgt
and buildDir
names. Obviously this cannot be done, as even the only top level rule that can be created with the action
function returns Rule ()
. What can i do instead?
I think you should be able to do:
shakeArgsWith opts additionalFlags $ \flags targets -> do
Stdout sout <- cmd (EchoStdout False) (EchoStderr False) "gcc -dumpmachine"
let arch = show (gccTripletToArch sout)
return $ Just $ do
let buildDir = bldDir </> show toolchain </> prettyShowArch arch </> show variant
...
buildDir <//> "*.o" %> \out -> do ...
The target patterns in Shake do have to be statically known, as that ensures some important properties with respect to quick rebuilding (you can guarantee a change in one place has predictable effects). However, you can run commands to determine things like arch, compiler version etc. before you create the build script, and bake them in.
Another viewpoint is that you are dynamically generated a build system based on the arch. Using Shake, as a Haskell EDSL, that is no particular problem, and you arguably were doing that before with the command line.