Skip to content

Commit 6f25722

Browse files
authored
build(gif): Add GIF library auto-build (#4921)
Fixes #4387 Added build_GIF.cmake module for GIF library dependency management. Since GIFLIB does not provide a CMakeLists.txt, I created a custom one that gets added to the cloned repository. The flow is similar to other libraries with cmake support, so I added a conditional statement in the build_dependency_with_cmake macro that, if a cmakelists.txt path is provided, will add/replace existing CMakeLists.txt files on the cloned repository. Signed-off-by: Valery Angelique <[email protected]>
1 parent b82f349 commit 6f25722

File tree

3 files changed

+334
-1
lines changed

3 files changed

+334
-1
lines changed

src/cmake/build_GIF.cmake

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright Contributors to the OpenImageIO project.
2+
# SPDX-License-Identifier: Apache-2.0
3+
# https://github.com/AcademySoftwareFoundation/OpenImageIO
4+
5+
######################################################################
6+
# GIF/GIFLIB
7+
# The original library does not have a CMake build system, so we
8+
# provide our own CMakeLists.txt template to build it.
9+
# See build_GIF_CMakeLists.txt for details.
10+
######################################################################
11+
12+
set_cache (GIF_BUILD_VERSION "5.2.1" "GIFLIB version for local builds")
13+
super_set (GIF_BUILD_GIT_REPOSITORY "https://git.code.sf.net/p/giflib/code")
14+
super_set (GIF_BUILD_GIT_TAG "${GIF_BUILD_VERSION}")
15+
set_cache (GIF_BUILD_SHARED_LIBS ${LOCAL_BUILD_SHARED_LIBS_DEFAULT}
16+
DOC "Should execute a local GIFLIB build; if necessary, build shared libraries" ADVANCED)
17+
18+
string (MAKE_C_IDENTIFIER ${GIF_BUILD_VERSION} GIF_VERSION_IDENT)
19+
20+
set (GIF_CMAKELISTS_TEMPLATE_PATH "${CMAKE_CURRENT_LIST_DIR}/build_GIF_CMakeLists.txt")
21+
build_dependency_with_cmake(GIF
22+
VERSION ${GIF_BUILD_VERSION}
23+
GIT_REPOSITORY ${GIF_BUILD_GIT_REPOSITORY}
24+
GIT_TAG ${GIF_BUILD_GIT_TAG}
25+
CMAKE_ARGS
26+
-D BUILD_SHARED_LIBS=${GIF_BUILD_SHARED_LIBS}
27+
)
28+
unset(GIF_CMAKELISTS_TEMPLATE_PATH)
29+
30+
31+
# Set some things up that we'll need for a subsequent find_package to work
32+
set (GIF_ROOT ${GIF_LOCAL_INSTALL_DIR})
33+
34+
# Signal to caller that we need to find again at the installed location
35+
find_package (GIF ${GIF_BUILD_VERSION} EXACT CONFIG REQUIRED)
36+
37+
if (GIF_BUILD_SHARED_LIBS)
38+
install_local_dependency_libs (GIF GIF)
39+
endif ()

src/cmake/build_GIF_CMakeLists.txt

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# Copyright Contributors to the OpenImageIO project.
2+
# SPDX-License-Identifier: Apache-2.0
3+
# https://github.com/AcademySoftwareFoundation/OpenImageIO
4+
5+
######################################################################
6+
# CMakeLists.txt for GIF/GIFLIB
7+
8+
# GIFLib repository doesn't have a cmakelists.txt included.
9+
# So when we clone the repository on build_GIF.cmake, we also want to
10+
# add this file as a "CMakeLists.txt" into the repository. This way
11+
# we can run it the same way with other libraries, following the same
12+
# logic as the build_with_cmake_macro
13+
14+
# Windows compatibility: Source code includes unistd.h, which is not available
15+
# on Windows systems. We patch source files to use appropriate Windows
16+
# alternatives and use these patched files (in GIF-build) instead of
17+
# the originals (GIF)
18+
######################################################################
19+
20+
cmake_minimum_required (VERSION @CMAKE_MINIMUM_REQUIRED_VERSION@)
21+
project(GIF VERSION @GIF_BUILD_VERSION@ LANGUAGES C)
22+
23+
# Options
24+
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
25+
option(BUILD_UTILS "Build utility programs" OFF)
26+
27+
28+
# Set MSVC specific flags and runtime
29+
if(MSVC)
30+
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
31+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
32+
33+
# Let runtime library be set by CMAKE_MSVC_RUNTIME_LIBRARY from command line
34+
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
35+
if(BUILD_SHARED_LIBS)
36+
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
37+
else()
38+
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
39+
endif()
40+
endif()
41+
42+
# Ensure proper DLL export/import
43+
if(BUILD_SHARED_LIBS)
44+
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
45+
endif()
46+
endif()
47+
48+
# replace #includes unistd to use windows equivalent
49+
if(WIN32)
50+
file(GLOB_RECURSE ORIGINAL_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
51+
52+
foreach(HEADER ${ORIGINAL_HEADERS})
53+
# Compute output path in build dir
54+
file(RELATIVE_PATH REL_PATH "${CMAKE_CURRENT_SOURCE_DIR}" "${HEADER}")
55+
set(OUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/${REL_PATH}")
56+
57+
# Make sure directory exists
58+
get_filename_component(OUT_DIR ${OUT_HEADER} DIRECTORY)
59+
file(MAKE_DIRECTORY ${OUT_DIR})
60+
61+
# Read header
62+
file(READ ${HEADER} CONTENTS)
63+
64+
# Add #ifdef guards to unistd.h
65+
if(CONTENTS MATCHES "#include <unistd.h>")
66+
string(REPLACE "#include <unistd.h>" "#ifdef _WIN32\n#include <io.h>\n#else\n#include <unistd.h>\n#endif" CONTENTS "${CONTENTS}")
67+
endif()
68+
69+
# Write patched header
70+
file(WRITE ${OUT_HEADER} "${CONTENTS}")
71+
72+
# Add patched directory to include path
73+
include_directories(${CMAKE_CURRENT_BINARY_DIR})
74+
endforeach()
75+
endif()
76+
77+
# Set output directories
78+
if(MSVC)
79+
# For MSVC, we want Debug and Release in separate directories
80+
foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
81+
string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
82+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG})
83+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/lib/${OUTPUTCONFIG})
84+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/lib/${OUTPUTCONFIG})
85+
endforeach()
86+
else()
87+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
88+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
89+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
90+
endif()
91+
92+
# Core library source files
93+
if (WIN32)
94+
# Use patched files from build directory
95+
set(GIF_SOURCES
96+
${CMAKE_CURRENT_BINARY_DIR}/dgif_lib.c
97+
${CMAKE_CURRENT_BINARY_DIR}/egif_lib.c
98+
${CMAKE_CURRENT_BINARY_DIR}/gif_err.c
99+
${CMAKE_CURRENT_BINARY_DIR}/gif_hash.c
100+
${CMAKE_CURRENT_BINARY_DIR}/gifalloc.c
101+
${CMAKE_CURRENT_BINARY_DIR}/openbsd-reallocarray.c
102+
${CMAKE_CURRENT_BINARY_DIR}/quantize.c
103+
)
104+
else()
105+
# Use original files on non-Windows platforms
106+
set(GIF_SOURCES
107+
dgif_lib.c
108+
egif_lib.c
109+
gif_err.c
110+
gif_hash.c
111+
gifalloc.c
112+
openbsd-reallocarray.c
113+
quantize.c
114+
)
115+
endif()
116+
117+
118+
# Define the GIF library
119+
if(BUILD_SHARED_LIBS)
120+
add_library(GIF SHARED ${GIF_SOURCES})
121+
122+
if (MSVC)
123+
# Add export definitions for Windows DLL
124+
target_compile_definitions(GIF
125+
PRIVATE -DGIF_EXPORTS
126+
PUBLIC -DGIF_DLL
127+
)
128+
endif()
129+
else()
130+
add_library(GIF STATIC ${GIF_SOURCES})
131+
endif()
132+
133+
# Create an alias target since we want to refer to it as GIF::GIF
134+
add_library(GIF::GIF ALIAS GIF)
135+
136+
# Set library properties
137+
set_target_properties(GIF PROPERTIES
138+
VERSION ${PROJECT_VERSION}
139+
SOVERSION ${PROJECT_VERSION_MAJOR}
140+
OUTPUT_NAME "GIF"
141+
# Ensure PIC just in case we need to link it into a shared library
142+
POSITION_INDEPENDENT_CODE ON
143+
)
144+
145+
# Add include path for GIFLIB
146+
if(WIN32)
147+
target_include_directories(GIF
148+
PUBLIC
149+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
150+
)
151+
else()
152+
target_include_directories(GIF
153+
PUBLIC
154+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
155+
)
156+
endif()
157+
158+
# Utility programs common source files
159+
if(WIN32)
160+
# Use patched files from build directory
161+
set(UTILS_COMMON_SOURCES
162+
${CMAKE_CURRENT_BINARY_DIR}/getarg.c
163+
${CMAKE_CURRENT_BINARY_DIR}/qprintf.c
164+
${CMAKE_CURRENT_BINARY_DIR}/gif_font.c
165+
)
166+
else()
167+
# Use original files on non-Windows platforms
168+
set(UTILS_COMMON_SOURCES
169+
getarg.c
170+
qprintf.c
171+
gif_font.c
172+
)
173+
endif()
174+
175+
# Define utility programs
176+
set(UTILS
177+
gif2rgb
178+
gifbuild
179+
gifbg
180+
gifclrmp
181+
gifcolor
182+
gifecho
183+
giffilter
184+
giffix
185+
gifhisto
186+
gifinto
187+
gifsponge
188+
giftext
189+
giftool #note: this requires getopt.c, which is not available on Windows
190+
gifwedge
191+
)
192+
193+
# Build utilities if enabled
194+
if(BUILD_UTILS)
195+
foreach(UTIL ${UTILS})
196+
add_executable(${UTIL} ${UTIL}.c ${UTILS_COMMON_SOURCES})
197+
target_link_libraries(${UTIL} PRIVATE GIF m)
198+
199+
# Set utility output properties
200+
set_target_properties(${UTIL} PROPERTIES
201+
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}"
202+
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}"
203+
PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
204+
)
205+
endforeach()
206+
endif()
207+
208+
# Installation
209+
include(GNUInstallDirs)
210+
211+
install(TARGETS GIF
212+
EXPORT GIFTargets
213+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
214+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
215+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
216+
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
217+
)
218+
219+
# Install headers
220+
if(WIN32)
221+
# Install patched headers from build directory
222+
install(FILES
223+
${CMAKE_CURRENT_BINARY_DIR}/gif_lib.h
224+
${CMAKE_CURRENT_BINARY_DIR}/gif_hash.h
225+
${CMAKE_CURRENT_BINARY_DIR}/gif_lib_private.h
226+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
227+
)
228+
else()
229+
# Install original headers on non-Windows platforms
230+
install(FILES
231+
gif_lib.h
232+
gif_hash.h
233+
gif_lib_private.h
234+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
235+
)
236+
endif()
237+
238+
# Install utilities
239+
if(BUILD_UTILS)
240+
install(TARGETS ${UTILS}
241+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
242+
)
243+
endif()
244+
245+
# Export targets
246+
install(EXPORT GIFTargets
247+
FILE GIFTargets.cmake
248+
NAMESPACE GIF::
249+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/GIF
250+
)
251+
252+
# Create and install config files
253+
include(CMakePackageConfigHelpers)
254+
255+
write_basic_package_version_file(
256+
"${CMAKE_CURRENT_BINARY_DIR}/GIFConfigVersion.cmake"
257+
VERSION ${PROJECT_VERSION}
258+
COMPATIBILITY SameMajorVersion
259+
)
260+
261+
# since we don't have a GIFConfig.cmake file in the source tree, we want to create
262+
# one and install it
263+
set(GIF_CONFIG_IN "
264+
@PACKAGE_INIT@
265+
include(\${CMAKE_CURRENT_LIST_DIR}/GIFTargets.cmake)
266+
check_required_components(GIF)
267+
")
268+
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GIFConfig.cmake.in" "${GIF_CONFIG_IN}")
269+
270+
configure_package_config_file(
271+
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/GIFConfig.cmake.in"
272+
"${CMAKE_CURRENT_BINARY_DIR}/GIFConfig.cmake"
273+
INSTALL_DESTINATION lib/cmake/GIF
274+
)
275+
276+
install(FILES
277+
"${CMAKE_CURRENT_BINARY_DIR}/GIFConfig.cmake"
278+
"${CMAKE_CURRENT_BINARY_DIR}/GIFConfigVersion.cmake"
279+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/GIF
280+
)

src/cmake/dependency_utils.cmake

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,10 @@ macro (build_dependency_with_cmake pkgname)
594594
${ARGN})
595595

596596
message (STATUS "Building local ${pkgname} ${_pkg_VERSION} from ${_pkg_GIT_REPOSITORY}")
597+
598+
if(DEFINED ${pkgname}_CMAKELISTS_TEMPLATE_PATH AND ${pkgname}_CMAKELISTS_TEMPLATE_PATH)
599+
message (STATUS "cmakelist template provided on: ${${pkgname}_CMAKELISTS_TEMPLATE_PATH}")
600+
endif()
597601

598602
set (${pkgname}_LOCAL_SOURCE_DIR "${${PROJECT_NAME}_LOCAL_DEPS_ROOT}/${pkgname}")
599603
set (${pkgname}_LOCAL_BUILD_DIR "${${PROJECT_NAME}_LOCAL_DEPS_ROOT}/${pkgname}-build")
@@ -651,6 +655,16 @@ macro (build_dependency_with_cmake pkgname)
651655
)
652656
endif ()
653657

658+
659+
# if a CMakeLists.txt path is specified, add it to the repository. This will replace existing ones
660+
# this should be set before calling the macro
661+
if(DEFINED ${pkgname}_CMAKELISTS_TEMPLATE_PATH AND NOT "${${pkgname}_CMAKELISTS_TEMPLATE_PATH}" STREQUAL "")
662+
message(STATUS "Adding custom CMakeLists.txt for ${pkgname}")
663+
configure_file("${${pkgname}_CMAKELISTS_TEMPLATE_PATH}"
664+
"${${pkgname}_LOCAL_SOURCE_DIR}/${_pkg_SOURCE_SUBDIR}/CMakeLists.txt"
665+
@ONLY)
666+
endif()
667+
654668
# Make sure to inherit CMAKE_IGNORE_PATH
655669
set(_pkg_CMAKE_ARGS ${_pkg_CMAKE_ARGS} ${_pkg_CMAKE_ARGS})
656670
if (CMAKE_IGNORE_PATH)
@@ -734,4 +748,4 @@ macro (alias_library_if_not_exists newalias realtarget)
734748
if (NOT TARGET ${newalias} AND TARGET ${realtarget})
735749
add_library(${newalias} ALIAS ${realtarget})
736750
endif ()
737-
endmacro ()
751+
endmacro ()

0 commit comments

Comments
 (0)