1cmake_minimum_required(VERSION 2.8.0)
2project(harfbuzz)
3
4enable_testing()
5
6## Limit framework build to Xcode generator
7if (BUILD_FRAMEWORK)
8  # for a framework on macOS, use `cmake .. -DBUILD_FRAMEWORK:BOOL=true -G Xcode`
9  if (NOT "${CMAKE_GENERATOR}" STREQUAL "Xcode")
10    message(FATAL_ERROR
11      "You should use Xcode generator with BUILD_FRAMEWORK enabled")
12  endif ()
13  set(CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_64_BIT)")
14  set(CMAKE_MACOSX_RPATH ON)
15  set(BUILD_SHARED_LIBS ON)
16endif ()
17
18
19## Disallow in-source builds, as CMake generated make files can collide with autotools ones
20if (NOT MSVC AND "${PROJECT_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}")
21  message(FATAL_ERROR
22    "
23In-source builds are not permitted!  Make a separate folder for"
24    " building, e.g.,"
25    "
26  mkdir build; cd build; cmake .."
27    "
28Before that, remove the files created by this failed run with"
29    "
30  rm -rf CMakeCache.txt CMakeFiles")
31endif ()
32
33
34## HarfBuzz build configurations
35option(HB_HAVE_FREETYPE "Enable freetype interop helpers" OFF)
36option(HB_HAVE_GRAPHITE2 "Enable Graphite2 complementary shaper" OFF)
37option(HB_BUILTIN_UCDN "Use HarfBuzz provided UCDN" ON)
38option(HB_HAVE_GLIB "Enable glib unicode functions" OFF)
39option(HB_HAVE_ICU "Enable icu unicode functions" OFF)
40if (APPLE)
41  option(HB_HAVE_CORETEXT "Enable CoreText shaper backend on macOS" ON)
42endif ()
43if (WIN32)
44  option(HB_HAVE_UNISCRIBE "Enable Uniscribe shaper backend on Windows" OFF)
45  option(HB_HAVE_DIRECTWRITE "Enable DirectWrite shaper backend on Windows" OFF)
46endif ()
47option(HB_BUILD_UTILS "Build harfbuzz utils, needs cairo, freetype, and glib properly be installed" OFF)
48if (HB_BUILD_UTILS)
49  set(HB_HAVE_GLIB ON)
50  set(HB_HAVE_FREETYPE ON)
51endif ()
52
53option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF)
54if (HB_HAVE_GOBJECT)
55  set(HB_HAVE_GLIB ON)
56endif ()
57
58option(HB_HAVE_INTROSPECTION "Enable building introspection (.gir/.typelib) files" OFF)
59if (HB_HAVE_INTROSPECTION)
60  set(HB_HAVE_GOBJECT ON)
61  set(HB_HAVE_GLIB ON)
62endif ()
63
64include_directories(AFTER
65  ${PROJECT_SOURCE_DIR}/src
66  ${PROJECT_BINARY_DIR}/src
67  )
68
69add_definitions(-DHAVE_OT)
70add_definitions(-DHAVE_FALLBACK)
71
72if (BUILD_SHARED_LIBS)
73  add_definitions(-DHAVE_ATEXIT)
74endif ()
75
76if (MSVC)
77  add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
78endif ()
79
80if (WIN32 AND NOT MINGW AND BUILD_SHARED_LIBS)
81  add_definitions("-DHB_EXTERN=__declspec(dllexport) extern")
82endif ()
83
84
85## Detect if we are running inside a distribution or regular repository folder
86set(IN_HB_DIST FALSE)
87if (EXISTS "${PROJECT_SOURCE_DIR}/ChangeLog")
88  # perhaps we are on dist directory
89  set(IN_HB_DIST TRUE)
90  set(HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h")
91endif ()
92
93
94## Extract variables from Makefile files
95# http://stackoverflow.com/a/27630120/1414809
96function (prepend var prefix)
97  set(listVar "")
98  foreach (f ${ARGN})
99    list(APPEND listVar "${prefix}${f}")
100  endforeach ()
101  set(${var} "${listVar}" PARENT_SCOPE)
102endfunction ()
103
104function (extract_make_variable variable file prefix)
105  string(REGEX MATCH "${variable} = ([^$]+)\\$" temp ${file})
106  string(REGEX MATCHALL "[^ \n\t\\]+" list ${CMAKE_MATCH_1})
107  prepend(list ${prefix} ${list})
108  set(${variable} ${list} PARENT_SCOPE)
109endfunction ()
110
111file(READ ${PROJECT_SOURCE_DIR}/src/Makefile.sources SRCSOURCES)
112file(READ ${PROJECT_SOURCE_DIR}/util/Makefile.sources UTILSOURCES)
113file(READ ${PROJECT_SOURCE_DIR}/src/hb-ucdn/Makefile.sources UCDNSOURCES)
114
115extract_make_variable(HB_BASE_sources ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
116extract_make_variable(HB_BASE_headers ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
117extract_make_variable(HB_FALLBACK_sources ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
118extract_make_variable(HB_OT_sources ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
119extract_make_variable(HB_OT_headers ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
120
121if (IN_HB_DIST)
122  set(RAGEL_GENERATED_DIR "${PROJECT_SOURCE_DIR}/src/")
123else ()
124  set(RAGEL_GENERATED_DIR "${PROJECT_BINARY_DIR}/src/")
125endif ()
126extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES} ${RAGEL_GENERATED_DIR})
127extract_make_variable(HB_OT_RAGEL_GENERATED_sources ${SRCSOURCES} ${RAGEL_GENERATED_DIR})
128
129extract_make_variable(HB_VIEW_sources ${UTILSOURCES} "${PROJECT_SOURCE_DIR}/util/")
130extract_make_variable(HB_SHAPE_sources ${UTILSOURCES} "${PROJECT_SOURCE_DIR}/util/")
131extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES} "${PROJECT_SOURCE_DIR}/util/")
132
133extract_make_variable(LIBHB_UCDN_sources ${UCDNSOURCES} "${PROJECT_SOURCE_DIR}/src/hb-ucdn/")
134
135file(READ configure.ac CONFIGUREAC)
136string(REGEX MATCH "\\[(([0-9]+)\\.([0-9]+)\\.([0-9]+))\\]" HB_VERSION_MATCH ${CONFIGUREAC})
137set(HB_VERSION ${CMAKE_MATCH_1})
138set(HB_VERSION_MAJOR ${CMAKE_MATCH_2})
139set(HB_VERSION_MINOR ${CMAKE_MATCH_3})
140set(HB_VERSION_MICRO ${CMAKE_MATCH_4})
141
142
143## Define ragel tasks
144if (NOT IN_HB_DIST)
145  find_program(RAGEL "ragel" CMAKE_FIND_ROOT_PATH_BOTH)
146
147  if (RAGEL)
148    message(STATUS "ragel found at: ${RAGEL}")
149  else ()
150    message(FATAL_ERROR "ragel not found, get it here -- http://www.complang.org/ragel/ or, use harfbuzz releases https://github.com/harfbuzz/harfbuzz/releases")
151  endif ()
152
153  foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources} ${HB_OT_RAGEL_GENERATED_sources})
154    string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output})
155    set(target_name ${CMAKE_MATCH_1})
156    add_custom_command(OUTPUT ${ragel_output}
157      COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN}
158      DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl
159      )
160    add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name})
161  endforeach ()
162
163  mark_as_advanced(RAGEL)
164endif ()
165
166
167## Generate hb-version.h
168if (NOT IN_HB_DIST)
169  set(HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in")
170  set(HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h")
171  set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true)
172  configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY)
173  execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different
174    "${HB_VERSION_H}.tmp"
175    "${HB_VERSION_H}"
176    )
177  file(REMOVE "${HB_VERSION_H}.tmp")
178endif ()
179
180
181## Define sources and headers of the project
182set(project_sources
183  ${HB_BASE_sources}
184  ${HB_BASE_RAGEL_GENERATED_sources}
185
186  ${HB_FALLBACK_sources}
187  ${HB_OT_sources}
188  ${HB_OT_RAGEL_GENERATED_sources}
189  )
190
191set(project_extra_sources)
192
193set(project_headers
194  ${HB_VERSION_H}
195
196  ${HB_BASE_headers}
197  ${HB_OT_headers}
198  )
199
200
201## Find and include needed header folders and libraries
202if (HB_HAVE_FREETYPE)
203
204  include(FindFreetype)
205  if (NOT FREETYPE_FOUND)
206    message(FATAL_ERROR "HB_HAVE_FREETYPE was set, but we failed to find it. Maybe add a CMAKE_PREFIX_PATH= to your Freetype2 install prefix")
207  endif()
208
209  list(APPEND THIRD_PARTY_LIBS ${FREETYPE_LIBRARIES})
210  include_directories(AFTER ${FREETYPE_INCLUDE_DIRS})
211  add_definitions(-DHAVE_FREETYPE=1 -DHAVE_FT_FACE_GETCHARVARIANTINDEX=1)
212
213  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ft.cc)
214  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-ft.h)
215
216endif ()
217
218if (HB_HAVE_GRAPHITE2)
219  add_definitions(-DHAVE_GRAPHITE2)
220
221  find_path(GRAPHITE2_INCLUDE_DIR graphite2/Font.h)
222  find_library(GRAPHITE2_LIBRARY graphite2)
223
224  include_directories(${GRAPHITE2_INCLUDE_DIR})
225
226  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-graphite2.cc)
227  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-graphite2.h)
228
229  list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY})
230
231  mark_as_advanced(GRAPHITE2_INCLUDE_DIR GRAPHITE2_LIBRARY)
232endif ()
233
234if (HB_BUILTIN_UCDN)
235  include_directories(src/hb-ucdn)
236  add_definitions(-DHAVE_UCDN)
237
238  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ucdn.cc)
239  list(APPEND project_extra_sources ${LIBHB_UCDN_sources})
240endif ()
241
242if (HB_HAVE_GLIB)
243  add_definitions(-DHAVE_GLIB)
244
245  # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindGLIB.cmake
246  find_package(PkgConfig)
247  pkg_check_modules(PC_GLIB QUIET glib-2.0)
248
249  find_library(GLIB_LIBRARIES NAMES glib-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS})
250  find_path(GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0/include)
251  find_path(GLIB_INCLUDE_DIR NAMES glib.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0)
252
253  include_directories(${GLIBCONFIG_INCLUDE_DIR} ${GLIB_INCLUDE_DIR})
254
255  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-glib.cc)
256  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-glib.h)
257
258  list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES})
259
260  mark_as_advanced(GLIB_LIBRARIES GLIBCONFIG_INCLUDE_DIR GLIB_INCLUDE_DIR)
261endif ()
262
263if (HB_HAVE_ICU)
264  add_definitions(-DHAVE_ICU)
265
266  # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindICU.cmake
267  find_package(PkgConfig)
268  pkg_check_modules(PC_ICU QUIET icu-uc)
269
270  find_path(ICU_INCLUDE_DIR NAMES unicode/utypes.h HINTS ${PC_ICU_INCLUDE_DIRS} ${PC_ICU_INCLUDEDIR})
271  find_library(ICU_LIBRARY NAMES libicuuc cygicuuc cygicuuc32 icuuc HINTS ${PC_ICU_LIBRARY_DIRS} ${PC_ICU_LIBDIR})
272
273  include_directories(${ICU_INCLUDE_DIR})
274
275  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-icu.cc)
276  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
277
278  list(APPEND THIRD_PARTY_LIBS ${ICU_LIBRARY})
279
280  mark_as_advanced(ICU_INCLUDE_DIR ICU_LIBRARY)
281endif ()
282
283if (APPLE AND HB_HAVE_CORETEXT)
284  # Apple Advanced Typography
285  add_definitions(-DHAVE_CORETEXT)
286
287  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc)
288  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h)
289
290  find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
291  if (APPLICATION_SERVICES_FRAMEWORK)
292    list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
293  endif (APPLICATION_SERVICES_FRAMEWORK)
294
295  mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
296endif ()
297
298if (WIN32 AND HB_HAVE_UNISCRIBE)
299  add_definitions(-DHAVE_UNISCRIBE)
300
301  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.cc)
302  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h)
303
304  list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
305endif ()
306
307if (WIN32 AND HB_HAVE_DIRECTWRITE)
308  add_definitions(-DHAVE_DIRECTWRITE)
309
310  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-directwrite.cc)
311  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
312
313  list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
314endif ()
315
316if (HB_HAVE_GOBJECT)
317  include(FindPythonInterp)
318  include(FindPerl)
319
320  # Use the hints from glib-2.0.pc to find glib-mkenums
321  find_package(PkgConfig)
322  pkg_check_modules(PC_GLIB QUIET glib-2.0)
323  find_program(GLIB_MKENUMS glib-mkenums
324    HINTS ${PC_glib_mkenums}
325    )
326  set(GLIB_MKENUMS_CMD)
327
328  if (WIN32 AND NOT MINGW)
329    # In Visual Studio builds, shebang lines are not supported
330    # in the standard cmd.exe shell that we use, so we need to
331    # first determine whether glib-mkenums is a Python or PERL
332    # script
333    execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${GLIB_MKENUMS}" --version
334      RESULT_VARIABLE GLIB_MKENUMS_PYTHON
335      OUTPUT_QUIET ERROR_QUIET
336      )
337    if (GLIB_MKENUMS_PYTHON EQUAL 0)
338      message("${GLIB_MKENUMS} is a Python script.")
339      set(GLIB_MKENUMS_CMD "${PYTHON_EXECUTABLE}" "${GLIB_MKENUMS}")
340    else ()
341      execute_process(COMMAND "${PERL_EXECUTABLE}" "${GLIB_MKENUMS}" --version
342        RESULT_VARIABLE GLIB_MKENUMS_PERL
343        OUTPUT_QUIET ERROR_QUIET
344        )
345      if (GLIB_MKENUMS_PERL EQUAL 0)
346        message("${GLIB_MKENUMS} is a PERL script.")
347        set(GLIB_MKENUMS_CMD "${PERL_EXECUTABLE}" "${GLIB_MKENUMS}")
348      endif ()
349      if (NOT GLIB_MKENUMS_PERL EQUAL 0 AND NOT GLIB_MKENUMS_PYTHON EQUAL 0)
350        message(FATAL_ERROR "Unable to determine type of glib-mkenums script")
351      endif ()
352	endif ()
353  else ()
354    set(GLIB_MKENUMS_CMD "${GLIB_MKENUMS}")
355  endif ()
356  if (NOT GLIB_MKENUMS_CMD)
357    message(FATAL_ERROR "HB_HAVE_GOBJECT was set, but we failed to find glib-mkenums, which is required")
358  endif()
359
360  pkg_check_modules(PC_GOBJECT QUIET gobject-2.0)
361
362  find_library(GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS})
363  find_path(GOBJECT_INCLUDE_DIR NAMES glib-object.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0)
364
365  include_directories(${GOBJECTCONFIG_INCLUDE_DIR} ${GOBJECT_INCLUDE_DIR})
366  mark_as_advanced(GOBJECT_LIBRARIES GOBJECT_INCLUDE_DIR)
367
368  list(APPEND hb_gobject_sources ${PROJECT_SOURCE_DIR}/src/hb-gobject-structs.cc)
369  list(APPEND hb_gobject_gen_sources
370    ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc
371    )
372  list(APPEND hb_gobject_structs_headers
373    ${PROJECT_SOURCE_DIR}/src/hb-gobject-structs.h
374    )
375  list(APPEND hb_gobject_headers
376    ${PROJECT_SOURCE_DIR}/src/hb-gobject.h
377    ${hb_gobject_structs_headers}
378    )
379  list(APPEND hb_gobject_gen_headers
380    ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
381    )
382
383  add_custom_command (
384    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
385    COMMAND ${GLIB_MKENUMS_CMD}
386      --template=${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.h.tmpl
387      --identifier-prefix hb_
388      --symbol-prefix hb_gobject
389      ${hb_gobject_structs_headers}
390      ${project_headers}
391      > ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h.tmp
392    COMMAND "${CMAKE_COMMAND}"
393      "-DENUM_INPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h.tmp"
394      "-DENUM_OUTPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h"
395      -P ${PROJECT_SOURCE_DIR}/replace-enum-strings.cmake
396    DEPENDS ${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.h.tmpl
397      ${hb_gobject_header}
398      ${project_headers}
399    )
400
401  add_custom_command (
402    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc
403    COMMAND ${GLIB_MKENUMS_CMD}
404      --template=${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.cc.tmpl
405      --identifier-prefix hb_
406      --symbol-prefix hb_gobject
407      ${hb_gobject_header}
408      ${project_headers}
409      > ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc.tmp
410    COMMAND "${CMAKE_COMMAND}"
411      "-DENUM_INPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc.tmp"
412      "-DENUM_OUTPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc"
413      -P ${PROJECT_SOURCE_DIR}/replace-enum-strings.cmake
414    DEPENDS ${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.cc.tmpl
415      ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
416      ${hb_gobject_header}
417      ${project_headers}
418    )
419endif ()
420
421## Atomic ops availability detection
422file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c"
423"		void memory_barrier (void) { __sync_synchronize (); }
424		int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
425		int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
426		void mutex_unlock (int *m) { __sync_lock_release (m); }
427		int main () { return 0; }
428")
429try_compile(HB_HAVE_INTEL_ATOMIC_PRIMITIVES
430  ${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives
431  SOURCES ${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c)
432if (HB_HAVE_INTEL_ATOMIC_PRIMITIVES)
433  add_definitions(-DHAVE_INTEL_ATOMIC_PRIMITIVES)
434endif ()
435
436file(WRITE "${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c"
437"		#include <atomic.h>
438		/* This requires Solaris Studio 12.2 or newer: */
439		#include <mbarrier.h>
440		void memory_barrier (void) { __machine_rw_barrier (); }
441		int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
442		void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
443		int main () { return 0; }
444")
445try_compile(HB_HAVE_SOLARIS_ATOMIC_OPS
446  ${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops
447  SOURCES ${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c)
448if (HB_HAVE_SOLARIS_ATOMIC_OPS)
449  add_definitions(-DHAVE_SOLARIS_ATOMIC_OPS)
450endif ()
451
452
453## Define harfbuzz library
454add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_headers})
455target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
456
457## Define harfbuzz-gobject library
458if (HB_HAVE_GOBJECT)
459  add_library(harfbuzz-gobject
460    ${hb_gobject_sources}
461    ${hb_gobject_gen_sources}
462    ${hb_gobject_headers}
463    ${hb_gobject_gen_headers}
464    )
465  include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/src)
466  add_dependencies(harfbuzz-gobject harfbuzz)
467  target_link_libraries(harfbuzz-gobject harfbuzz ${GOBJECT_LIBRARIES} ${THIRD_PARTY_LIBS})
468endif ()
469
470# On Windows, g-ir-scanner requires a DLL build in order for it to work
471if (WIN32)
472  if (NOT BUILD_SHARED_LIBS)
473    message("Building introspection files on Windows requires BUILD_SHARED_LIBS to be enabled.")
474    set(HB_HAVE_INTROSPECTION OFF)
475  endif ()
476endif ()
477
478if (HB_HAVE_INTROSPECTION)
479
480  find_package(PkgConfig)
481  pkg_check_modules(PC_GI QUIET gobject-introspection-1.0)
482
483  find_program(G_IR_SCANNER g-ir-scanner
484    HINTS ${PC_g_ir_scanner}
485    )
486
487  find_program(G_IR_COMPILER g-ir-compiler
488    HINTS ${PC_g_ir_compiler}
489    )
490
491  if (WIN32 AND NOT MINGW)
492    # Note that since we already enable HB_HAVE_GOBJECT
493    # we would already have PYTHON_EXECUTABLE handy
494    set(G_IR_SCANNER_CMD "${PYTHON_EXECUTABLE}" "${G_IR_SCANNER}")
495  else ()
496    set(G_IR_SCANNER_CMD "${G_IR_SCANNER}")
497  endif ()
498
499  # We need to account for the varying output directories
500  # when we build using Visual Studio projects
501  if("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
502    set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
503  else ()
504    set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
505  endif ()
506
507  # Get the CFlags that we used to build HarfBuzz/HarfBuzz-GObject
508  set (hb_defines_cflags "")
509  foreach(hb_cflag ${hb_cflags})
510    list(APPEND hb_defines_cflags "-D${hb_cflag}")
511  endforeach(hb_cflag)
512
513  # Get the other dependent libraries we used to build HarfBuzz/HarfBuzz-GObject
514  set (extra_libs "")
515  foreach (extra_lib ${THIRD_PARTY_LIBS})
516    # We don't want the .lib extension here...
517    string(REPLACE ".lib" "" extra_lib_stripped "${extra_lib}")
518    list(APPEND extra_libs "--extra-library=${extra_lib_stripped}")
519  endforeach ()
520
521  set(introspected_sources)
522  foreach (f
523    ${project_headers}
524    ${project_sources}
525    ${hb_gobject_gen_sources}
526    ${hb_gobject_gen_headers}
527    ${hb_gobject_sources}
528    ${hb_gobject_headers}
529    )
530    if (WIN32)
531      # Nasty issue: We need to make drive letters lower case,
532      # otherwise g-ir-scanner won't like it and give us a bunch
533      # of invalid items and unresolved types...
534      STRING(SUBSTRING "${f}" 0 1 drive)
535      STRING(SUBSTRING "${f}" 1 -1 path)
536      if (drive MATCHES "[A-Z]")
537        STRING(TOLOWER ${drive} drive_lower)
538        list(APPEND introspected_sources "${drive_lower}${path}")
539      else ()
540        list(APPEND introspected_sources "${f}")
541      endif ()
542    else ()
543      list(APPEND introspected_sources "${f}")
544    endif ()
545  endforeach ()
546
547  # Finally, build the introspection files...
548  add_custom_command (
549    TARGET harfbuzz-gobject
550    POST_BUILD
551    COMMAND ${G_IR_SCANNER_CMD}
552      --warn-all --no-libtool --verbose
553      -n hb
554      --namespace=HarfBuzz
555      --nsversion=0.0
556      --identifier-prefix=hb_
557      --include GObject-2.0
558      --pkg-export=harfbuzz
559      --cflags-begin
560      -I${PROJECT_SOURCE_DIR}/src
561      -I${PROJECT_BINARY_DIR}/src
562      ${hb_includedir_cflags}
563      ${hb_defines_cflags}
564      -DHB_H
565      -DHB_H_IN
566      -DHB_OT_H
567      -DHB_OT_H_IN
568      -DHB_GOBJECT_H
569      -DHB_GOBJECT_H_IN
570      -DHB_EXTERN=
571      --cflags-end
572      --library=harfbuzz-gobject
573      --library=harfbuzz
574      -L${hb_libpath}
575      ${extra_libs}
576      ${introspected_sources}
577      -o ${hb_libpath}/HarfBuzz-0.0.gir
578    DEPENDS harfbuzz-gobject harfbuzz
579    )
580
581  add_custom_command (
582    TARGET harfbuzz-gobject
583    POST_BUILD
584    COMMAND "${G_IR_COMPILER}"
585      --verbose --debug
586      --includedir ${CMAKE_CURRENT_BINARY_DIR}
587      ${hb_libpath}/HarfBuzz-0.0.gir
588      -o ${hb_libpath}/HarfBuzz-0.0.typelib
589    DEPENDS ${hb_libpath}/HarfBuzz-0.0.gir harfbuzz-gobject
590    )
591endif ()
592
593## Additional framework build configs
594if (BUILD_FRAMEWORK)
595  set(CMAKE_MACOSX_RPATH ON)
596  set_target_properties(harfbuzz PROPERTIES
597    FRAMEWORK TRUE
598    PUBLIC_HEADER "${project_headers}"
599    XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
600  )
601  set(MACOSX_FRAMEWORK_IDENTIFIER "harfbuzz")
602  set(MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${HB_VERSION}")
603  set(MACOSX_FRAMEWORK_BUNDLE_VERSION "${HB_VERSION}")
604endif ()
605
606
607## Additional harfbuzz build artifacts
608if (HB_BUILD_UTILS)
609  # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindCairo.cmake
610  find_package(PkgConfig)
611  pkg_check_modules(PC_CAIRO QUIET cairo)
612
613  find_path(CAIRO_INCLUDE_DIRS NAMES cairo.h HINTS ${PC_CAIRO_INCLUDEDIR} ${PC_CAIRO_INCLUDE_DIRS} PATH_SUFFIXES cairo)
614  find_library(CAIRO_LIBRARIESNAMES cairo HINTS ${PC_CAIRO_LIBDIR} ${PC_CAIRO_LIBRARY_DIRS})
615
616  add_definitions("-DPACKAGE_NAME=\"HarfBuzz\"")
617  add_definitions("-DPACKAGE_VERSION=\"${HB_VERSION}\"")
618  include_directories(${CAIRO_INCLUDE_DIRS})
619
620  add_executable(hb-view ${HB_VIEW_sources})
621  target_link_libraries(hb-view harfbuzz ${CAIRO_LIBRARIESNAMES})
622
623  add_executable(hb-shape ${HB_SHAPE_sources})
624  target_link_libraries(hb-shape harfbuzz)
625
626  add_executable(hb-ot-shape-closure ${HB_OT_SHAPE_CLOSURE_sources})
627  target_link_libraries(hb-ot-shape-closure harfbuzz)
628
629  mark_as_advanced(CAIRO_INCLUDE_DIRS CAIRO_LIBRARIESNAMES)
630endif ()
631
632
633## Install
634if (NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL)
635  install(FILES ${project_headers} DESTINATION include/harfbuzz)
636  if (HB_HAVE_GOBJECT)
637    install(FILES ${hb_gobject_headers} ${hb_gobject_gen_headers} DESTINATION include/harfbuzz)
638  endif ()
639endif ()
640
641if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
642  install(TARGETS harfbuzz
643    ARCHIVE DESTINATION lib
644    LIBRARY DESTINATION lib
645    RUNTIME DESTINATION bin
646    FRAMEWORK DESTINATION Library/Frameworks
647    )
648  if (HB_BUILD_UTILS)
649    install(TARGETS hb-view
650      RUNTIME DESTINATION bin
651    )
652    install(TARGETS hb-view
653      RUNTIME DESTINATION bin
654    )
655
656    install(TARGETS hb-shape
657      RUNTIME DESTINATION bin
658    )
659
660    install(TARGETS hb-ot-shape-closure
661      RUNTIME DESTINATION bin
662    )
663  endif ()
664  if (HB_HAVE_GOBJECT)
665    install(TARGETS harfbuzz-gobject
666      ARCHIVE DESTINATION lib
667      LIBRARY DESTINATION lib
668      RUNTIME DESTINATION bin
669    )
670    if (HB_HAVE_INTROSPECTION)
671      if("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
672        set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
673      else ()
674        set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
675      endif ()
676
677      install(FILES "${hb_libpath}/HarfBuzz-0.0.gir"
678        DESTINATION share/gir-1.0
679        )
680
681      install(FILES "${hb_libpath}/HarfBuzz-0.0.typelib"
682        DESTINATION lib/girepository-1.0
683        )
684    endif ()
685  endif ()
686endif ()
687
688# Needs to come last so that variables defined above are passed to
689# subdirectories.
690add_subdirectory(test)
691