我正在运行macOS 10.15的计算机上编译一个项目,该项目将旧版本的libpng(1.6.17)作为子模块提供。相应的代码位于https://github.com/glennrp/libpng。我也有Homebrew安装的libpng 1.6.37。
直到不久前,我才能够使用CMake轻松编译libpng 1.6.17。由于最近(但我不知道确切的日期),因此构建失败并显示以下错误:
FAILED: CMakeFiles/png16_static.dir/pngwutil.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -I/usr/local/include -I. -I../ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -MD -MT CMakeFiles/png16_static.dir/pngwutil.o -MF CMakeFiles/png16_static.dir/pngwutil.o.d -o CMakeFiles/png16_static.dir/pngwutil.o -c ../pngwutil.c
../pngwutil.c:2413:20: error: use of undeclared identifier 'PNG_WEIGHT_SHIFT'
PNG_WEIGHT_SHIFT;
^
我对我的项目的副本进行了一些检查,该项目的副本仍可正确编译,因为CMake并未在其上重新运行自身。两种情况之间的唯一区别是在编译器调用中添加了-I/usr/local/include
标志(我添加了一些标记以帮助查看区别):
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -Dpng16_EXPORTS -Iext_build/libpng -I../../ext/libpng -O3 -DNDEBUG -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -fPIC -fno-stack-protector -fomit-frame-pointer -fno-math-errno -ffp-contract=fast -march=native -MD -MT ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -MF ext_build/libpng/CMakeFiles/png16.dir/pngrio.o.d -o ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -c ../../ext/libpng/pngrio.c
<---------------------------------->
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -Dpng16_EXPORTS -I/usr/local/include -Iext_build/libpng -I../../ext/libpng -O3 -DNDEBUG -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -fPIC -fno-stack-protector -fomit-frame-pointer -fno-math-errno -ffp-contract=fast -march=native -MD -MT ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -MF ext_build/libpng/CMakeFiles/png16.dir/pngrio.o.d -o ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -c ../../ext/libpng/pngrio.c
<------------------------------------------------------->
我在正在运行的项目副本上重新运行CMake,但遇到了相同的错误,这使我指出了与系统相关的问题。然后,我直接检出了libpng源,并得到了相同的错误。
git clone https://github.com/glennrp/libpng.git
cd libpng
git checkout v1.6.17
cmake . -B build && cmake --build build
将此-I/usr/local/include
标志添加到我的编译器调用中的原因是什么?
现在,它很有趣。如果您签出较新的libpng(我尝试使用1.6.21、1.6.25、1.6.28、1.6.33和1.6.37),则问题会消失,尽管该标志仍然在此处:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -I/usr/local/include -I. -I../ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -MD -MT CMakeFiles/png16_static.dir/pngrio.o -MF CMakeFiles/png16_static.dir/pngrio.o.d -o CMakeFiles/png16_static.dir/pngrio.o -c ../pngrio.c
这意味着我可以使用这些发行版之一来更新子模块,而我的问题将消失。
但是,如果我没记错的话,-I
标志是从左到右解析的:因此,我怀疑我使用的Homebrew标头代替了源标头。如果我是对的,那么这不能保证libpng的Homebrew升级不会再次破坏构建:它只是表明libpng的API自v1.6.21以来一直是稳定的,并且我可以将Homebrew标头与源一起使用我正在尝试编译。我是对的还是我错过了什么?
是的,有时cmake会拾取各种库,包括dirs,并自由地混合和匹配。如果需要保持多个版本,则应使用cmake命令传递正确的软件包。
我终于找到答案了。原来,libpng的zlib依赖关系(间接地)给我带来了麻烦。
MacOS附带了zlib,开发人员通常知道它,因此他们不需要安装第三方zlib。但是,CMake的find_package
不了解此首选项,并且会选择/usr/local
中的zlib实现,例如,如果它是由Homewbrew安装的。由于某种原因,第3方软件在我的系统上的该位置安装了zlib,而不是Homebrew软件包,这使得检测更加困难,并由find_package
进行了检测。
相应的包含目录是/usr/local/include
。 libpng的CMake代码是这样的,然后将该目录添加到包含目录的列表中,这会导致问题中提到的标头冲突。我了解通过CMakeCache.txt
(搜索/usr/local/include
)发生的情况,所以主要的教训是:在这种情况下,请不要忘记检查您的CMake缓存。
懒惰的方式。删除不需要的lib文件。我运行了brew doctor
并删除了不应该在这里的文件。但是,如果某些软件实际上需要/usr/local
中的特定zlib版本,则可能会产生不希望的结果。
CMake肮脏的方式。修改顶级CMake代码以提示find_package
有关应该在哪里选择zlib。您可以使用find_package
参数对提示进行硬编码,也可以使用PATHS
参数进行设置(您可能需要为此定义策略)。
[我敢肯定,有一种更好的方法可以通过libpng中的ZLIB_ROOT
处理并在系统路径中强制执行库搜索,但是我的CMake技能不足以说出应该做什么。而且,相对于该问题而言,它有点偏离主题。