将Make构建迁移至Shake后,如何捕获C项目的Include目录?
我之前在把Make迁移到Shake的C项目里也踩过这个头文件目录监控的坑,分享几个亲测有效的解决方案帮你提升鲁棒性:
方案1:递归扫描头文件+显式监控目录结构
Shake默认的getDirectoryFiles如果只指定文件模式,不会自动监控新增的子目录。你可以改成递归扫描所有头文件,同时额外监控inc目录下的所有子目录,这样新增/删除子目录时会触发重新扫描:
main = shakeArgs shakeOptions $ do -- 递归获取inc下所有头文件(包括子目录) incFiles <- getDirectoryFiles "inc" ["//*.h", "//*.hpp"] -- 显式监控inc下的所有子目录,捕获目录结构变更 void $ getDirectoryFiles "inc" ["//"] -- 后续编译规则中,把incFiles作为依赖项 "build//*.o" %> \out -> do let srcFile = replaceDirectory out "src" -<.> "c" need $ srcFile : incFiles cmd "gcc -c" srcFile "-o" out "-Iinc" (map ("-Iinc/"++) <$> getDirectoryFiles "inc" ["*"])
方案2:为inc子目录创建伪依赖规则
你可以给inc目录下的每个子目录创建一个伪目标,让Shake监控这些目录的存在变化。当新增子目录时,伪目标会触发重新评估:
main = shakeArgs shakeOptions $ do -- 定义规则:监控inc下的所有子目录 "inc//*" %> \dir -> do -- 只要目录存在或结构变化,就触发重新扫描该目录下的头文件 void $ getDirectoryFiles dir ["*.h", "*.hpp"] return () -- 获取所有inc子目录并加入依赖 incDirs <- getDirectoryFiles "inc" ["*"] need $ map ("inc/"++) incDirs -- 正常处理源文件和编译逻辑 srcFiles <- getDirectoryFiles "src" ["//*.c"] forM_ srcFiles $ \src -> do let out = "build/" ++ src -<.> "o" out %> \_ -> do incFiles <- getDirectoryFiles "inc" ["//*.h"] need $ src : incFiles cmd "gcc -c" src "-o" out "-Iinc" (map ("-Iinc/"++) incDirs)
方案3:用watch函数全局监控inc目录
Shake的watch函数可以显式指定要监控的路径,包括目录。直接监控inc下的所有内容,任何目录结构变更都会触发构建系统重新评估:
main = shakeArgs shakeOptions $ do -- 全局监控inc目录及其所有子目录和文件 watch "inc//*" -- 正常获取并处理源文件和头文件 srcFiles <- getDirectoryFiles "src" ["//*.c"] incFiles <- getDirectoryFiles "inc" ["//*.h"] "build//*.o" %> \out -> do let src = replaceDirectory out "src" -<.> "c" need $ src : incFiles cmd "gcc -c" src "-o" out "-Iinc" (map ("-I"++) <$> getDirectoryFiles "inc" ["*"])
关键原理说明
之前你抓不到inc目录变化的核心原因是:Shake默认只会监控已经扫描到的文件,而不会主动监控目录结构的新增/删除。通过上面的方法,要么显式依赖目录本身,要么用watch强制监控目录路径,就能让Shake感知到inc目录结构的变更,自动重新扫描头文件,避免手动重建构建系统。
内容的提问来源于stack exchange,提问作者Oceanofthelost
相关产品推荐
相关产品推荐

