GDAL的编译脚本呈现出不同平台不同解决方案的百花齐放现状。我是从windows平台开始编译GDAL的,用的自然是nmake。那就是一种每个目录下都需要写makefile文件的构建方法,写的人麻烦,我因为要定制,也是不甚其烦。
基于前文:premake 在64位Ubuntu系统下编译32位GCC程序的基础,我在Ubuntu上构建了premake脚本,可以编译出debug64, debug32, release64和releae32的gdal动态和静态库。由于我所用的gdal是定制版本的,可能有所不同,下面的共参考。
创建一个config.lua脚本文件,内容如下:
-- A solution contains projects, and defines the available configurations solution ("gdal") configurations {"Debug64","Release64", "Debug32", "Release32"} location "build" includedirs { "/usr/src/linux-headers-3.8.0-30-generic/include/config/pci/", "/usr/include/x86_64-linux-gnu/c++/4.8" } configuration "Debug64" targetdir "output/linux_debug_x64" defines { "DEBUG", "HAVE_SSE_AT_COMPILE_TIME" } flags {"Symbols"} configuration "Debug32" targetdir "output/linux_debug_x32" defines { "DEBUG", "HAVE_SSE_AT_COMPILE_TIME" } buildoptions {"-m32"} linkoptions {"-m32"} flags {"Symbols"} configuration "Release64" targetdir "output/linux_release_x64" defines { "NDEBUG", "HAVE_SSE_AT_COMPILE_TIME" } flags {"OptimizeSize"} configuration "Release32" targetdir "output/linux_release_x32" defines { "NDEBUG", "HAVE_SSE_AT_COMPILE_TIME" } buildoptions {"-m32"} linkoptions {"-m32"} flags {"OptimizeSize"} -- project port defines one build target p = project("port") basedir(p.name) location("build/" .. p.name) kind "SharedLib" language "C++" files { p.name .. "/*.h", p.name .. "/*.cpp" } excludes { p.name .. "/cpl_vsil_stdout.cpp", p.name .. "/cpl_odbc.cpp", p.name .. "/cpl_win32ce_api.cpp", p.name .. "/cpl_vsil_simple.cpp", p.name .. "/cpl_vsil_win32.cpp", p.name .. "/cpl_vsil_gzip.cpp", p.name .. "/cpl_vsil_buffered_reader.cpp", p.name .. "/cpl_minizip_zip", p.name .. "/cpl_minizip_zip.cpp", p.name .. "/cpl_minizip_unzip.cpp", p.name .. "/xmlreformat.cpp", p.name .. "/cpl_vsil_tar.cpp", p.name .. "/cpl_quad_tree.cpp", p.name .. "/cpl_vsil_readahead_reader.cp", p.name .. "/cpl_google_oauth2.cpp", p.name .. "/cpl_vsil_curl.cpp", p.name .. "/cpl_vsil_curl_streaming.cpp", p.name .. "/cpl_minizip_ioapi.cpp", p.name .. "/cpl_vsil_abstract_archive.cpp", p.name .. "/cpl_vsil_cache.cpp", p.name .. "/cpl_spawn.cpp" } includedirs { "./port", "./ogr", "./gcore", "./alg", "./ogr/ogrsf_frmts", "./frmts/zlib" } -- project ogr defines one build target p = project("ogr") basedir(p.name) location("build/" .. p.name) -- build .a here because nmake generats ogr.lib kind "StaticLib" language "C++" files { p.name .. "/*.c", p.name .. "/*.cpp" } excludes { p.name .. "/ogrlinearring.cpp", p.name .. "/ogrutils.cpp", p.name .. "/ogr2gmlgeometry.cpp", p.name .. "/ogrmultipoint.cpp", p.name .. "/ogrmultipolygon.cpp", p.name .. "/ogrfeaturestyle.cpp", p.name .. "/swq_op_registrar.cpp", p.name .. "/ogr_api.cpp", p.name .. "/ogrsurface.cpp", p.name .. "/ogrfielddefn.cpp", p.name .. "/ogr_opt.cpp", p.name .. "/ogrmultilinestring.cpp", p.name .. "/ogrfeature.cpp", p.name .. "/swq.cpp", p.name .. "/ogrgeometrycollection.cpp", p.name .. "/ogrcurve.cpp", p.name .. "/gml2ogrgeometry.cpp", p.name .. "/ograssemblepolygon.cpp", p.name .. "/ogrfeaturequery.cpp", p.name .. "/ogrgeometry.cpp", p.name .. "/swq_op_general.cpp", p.name .. "/ogrgeometryfactory.cpp", p.name .. "/ogrlinestring.cpp", p.name .. "/swq_parser.cpp", p.name .. "/ogrpolygon.cpp", p.name .. "/swq_select.cpp", p.name .. "/swq_expr_node.cpp", p.name .. "/ogrpoint.cpp", p.name .. "/ogrfeaturedefn.cpp", } includedirs { "./port", "./ogr", "./gcore", "./alg", "./ogr/ogrsf_frmts", "./ogrsf_frmts", "./frmts/gtiff/libgeotiff" } -- project ogr defines one build target p = project("gcore") basedir(p.name) location("build/" .. p.name) kind "SharedLib" language "C++" files { p.name .. "/*.h", p.name .. "/*.cpp" } excludes { p.name .. "/gdaljp2metadata.cpp", p.name .. "/gdaljp2box.cpp", p.name .. "/gdalgmlcoverage.cpp" } includedirs { "./port", "./ogr", "./gcore", "./alg", "./ogr/ogrsf_frmts", "./ogrsf_frmts", "./frmts/gtiff" } -- project frmts defines one build target -- After this last project build is finished, then link all obj and libs to library p = project("frmts") basedir(p.name) location("build/" .. p.name) kind "SharedLib" language "C++" files { p.name .. "/*.cpp", p.name .. "/jpeg/*.cpp", p.name .. "/jpeg/*.c", p.name .. "/nitf/*.cpp", p.name .. "/nitf/*.c", p.name .. "/gtiff/*.cpp", p.name .. "/gtiff/*.c", p.name .. "/gtiff/libtiff/*.c", p.name .. "/gtiff/libgeotiff/*.c", p.name .. "/jpeg/*.cpp", p.name .. "/jpeg/*.c", p.name .. "/dted/*.cpp", p.name .. "/dted/*.c", p.name .. "/zlib/*.cpp", p.name .. "/zlib/*.c" } excludes { p.name .. "/nitf/rpftocdataset.cpp", p.name .. "/nitf/nitfdump.c", p.name .. "/dted/dted_test.c", p.name .. "/dted/dteddataset.cpp", p.name .. "/gtiff/libtiff/tif_print.c", p.name .. "/gtiff/libgeotiff/geo_trans.c", p.name .. "/zlib/gzio.c" } includedirs { "./port", "./ogr", "./gcore", "./alg", "./ogr/ogrsf_frmts", "./frmts/zlib", "./frmts/jpeg/libjpeg", "./frmts/gtiff/libtiff", "./frmts/vrt", "./frmts/gtiff/libgeotiff", "./frmts/jpeg/jpeg-8c" } defines { "FRMT_nitf", "DFRMT_gtiff", "FRMT_jpeg", "FRMT_dted", "FRMT_zlib" }
整个设计是用一个solution包含四个project,分别对应GDAL的port, ogr, gcore和frmts目录下的代码。premake会自动为每个项目build出动态或者静态库。但是premake4还没有办法在编译时知道自己的configuration是什么(这个功能要到premake5.0才有)。为了弥补这个缺憾,我写了四个脚本,分别在最后将所有的*.o和*.a文件link成libgdal.so和libgdal.a文件。
比如rebuild_linxu_debug_32.sh文件,
export CXX=clang++ export CC=clang rm -rf build rm -rf output/linux_debug_x32 ../../../depfiles/build/linux/premake4 --file=config.lua gmake cd build make config=debug32 cd - $CXX -o output/linux_debug_x32/libgdal.so build/port/obj/Debug32/*.o output/linux_debug_x32/libogr.a build/gcore/obj/Debug32/*.o build/frmts/obj/Debug32/*.o -m32 -shared ar -rcs output/linux_debug_x32/libgdal.a build/port/obj/Debug32/*.o output/linux_debug_x32/libogr.a build/gcore/obj/Debug32/*.o build/frmts/obj/Debug32/*.o
这里可以看到,我用的是clang编译器,去掉开头两行,就变成了gcc了。其他脚本类似。
最后有一个rebuild.sh脚本,编译出所有的版本。
rm -rf output ./rebuild_linux_debug_64.sh ./rebuild_linux_release_64.sh ./rebuild_linux_debug_32.sh ./rebuild_linux_release_32.sh
就在顶层目录下搞定,再也不需要维护那么多makefile了。