• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1project(
2    'libxml2',
3    'c',
4    version: '2.13.0',
5    license: 'MIT',
6    default_options: ['buildtype=debug', 'warning_level=3'],
7    meson_version: '>= 0.61',
8)
9
10v_array = meson.project_version().split('.')
11v_maj = v_array[0]
12v_min = v_array[1]
13v_mic = v_array[2]
14v_nbr = v_maj.to_int() * 10000 + v_min.to_int() * 100 + v_mic.to_int()
15v_extra = ''
16r = run_command('git', 'describe', check: false)
17if (r.returncode() == 0)
18    v_extra = '-GIT' + r.stdout().strip()
19endif
20
21# install paths
22dir_prefix = get_option('prefix')
23dir_bin = dir_prefix / get_option('bindir')
24dir_include = dir_prefix / get_option('includedir')
25dir_pkginclude = dir_include / meson.project_name()
26dir_lib = dir_prefix / get_option('libdir')
27dir_data = dir_prefix / get_option('datadir')
28dir_doc = dir_data / 'doc' / 'libxml2'
29dir_locale = dir_prefix / get_option('localedir')
30
31# host
32
33host_os = host_machine.system()
34
35cygwin = 'cygwin'
36windows = 'windows'
37sys_cygwin = cygwin.contains(host_os)
38sys_windows = windows.contains(host_os)
39
40libxml2_cflags = []
41xml_cflags = ''
42dep_args = []
43
44if sys_cygwin or sys_windows
45    if get_option('default_library') == 'static'
46        xml_cflags = '-DLIBXML_STATIC'
47        libxml2_cflags += '-DLIBXML_STATIC'
48        dep_args += '-DLIBXML_STATIC'
49    endif
50endif
51
52# binaries
53cc = meson.get_compiler('c')
54
55# options
56want_c14n = get_option('c14n')
57want_catalog = get_option('catalog')
58want_debug = get_option('debuging')
59want_history = get_option('history')
60want_html = get_option('html')
61want_http = get_option('http')
62want_ipv6 = get_option('ipv6')
63want_iso8859x = get_option('iso8859x')
64want_legacy = get_option('legacy')
65want_output = get_option('output')
66want_pattern = get_option('pattern')
67want_push = get_option('push')
68want_python = get_option('python')
69want_reader = get_option('reader')
70want_readline = get_option('readline')
71want_regexps = get_option('regexps')
72want_sax1 = get_option('sax1')
73want_schemas = get_option('schemas')
74want_schematron = get_option('schematron')
75want_thread_alloc = get_option('thread-alloc')
76want_tls = get_option('tls')
77want_tree = get_option('tree')
78want_valid = get_option('valid')
79want_writer = get_option('writer')
80want_xinclude = get_option('xinclude')
81want_xpath = get_option('xpath')
82want_xptr = get_option('xptr')
83
84# TODO: Options should be three-valued: "yes", "no", default
85
86# TODO: Legacy defaults
87
88# hard dependencies on options
89
90if want_c14n == true
91    if want_output == false
92        message('-Dc14n=true overrides -Doutput')
93    endif
94    want_output = true
95    if want_xpath == false
96        message('-Dc14n=true overrides -Dxpath')
97    endif
98    want_xpath = true
99endif
100
101if want_schemas == true
102    if want_pattern == false
103        message('-Dschemas=true overrides -Dpattern')
104    endif
105    want_pattern = true
106    if want_regexps == false
107        message('-Dschemas=true overrides -Dregexps')
108    endif
109    want_regexps = true
110endif
111
112if want_schematron == true
113    if want_pattern == false
114        message('-Dschematron=true overrides -Dpattern')
115    endif
116    want_pattern = true
117    if want_tree == false
118        message('-Dschematron=true overrides -Dtree')
119    endif
120    want_tree = true
121    if want_xpath == false
122        message('-Dschematron=true overrides -Dxpath')
123    endif
124    want_xpath = true
125endif
126
127if want_reader == true
128    if want_push == false
129        message('-Dreader=true overrides -Dpush')
130    endif
131    want_push = true
132    if want_tree == false
133        message('-Dreader=true overrides -Dtree')
134    endif
135    want_tree = true
136endif
137
138if want_writer == true
139    if want_output == false
140        message('-Dwriter=true overrides -Doutput')
141    endif
142    want_output = true
143    if want_push == false
144        message('-Dwriter=true overrides -Dpush')
145    endif
146    want_push = true
147endif
148
149if want_xinclude == true
150    if want_xpath == false
151        message('-Dxinclude=true overrides -Dxpath')
152    endif
153    want_xpath = true
154endif
155
156if want_xptr == true
157    if want_xpath == false
158        message('-Dxptr=true overrides -Dxpath')
159    endif
160    want_xpath = true
161endif
162
163# minimum dependencies
164
165if get_option('minimum')
166    # TODO: This is should allow other options
167    want_c14n = false
168    want_catalog = false
169    want_debug = false
170    want_history = false
171    want_html = false
172    want_http = false
173    want_ipv6 = false
174    want_iso8859x = false
175    want_output = false
176    want_pattern = false
177    want_push = false
178    want_python = false
179    want_reader = false
180    want_readline = false
181    want_regexps = false
182    want_sax1 = false
183    want_schemas = false
184    want_schematron = false
185    want_thread_alloc = false
186    want_tree = false
187    want_valid = false
188    want_writer = false
189    want_xinclude = false
190    want_xpath = false
191    want_xptr = false
192else
193    # Disable dependent modules
194    if want_output == false
195        want_c14n = false
196        want_writer = false
197    endif
198    if want_pattern == false
199        want_schemas = false
200        want_schematron = false
201    endif
202    if want_push == false
203        want_reader = false
204        want_writer = false
205    endif
206    if want_regexps == false
207        want_schemas = false
208    endif
209    if want_tree == false
210        want_reader = false
211        want_schematron = false
212    endif
213    if want_xpath == false
214        want_c14n = false
215        want_schematron = false
216        want_xinclude = false
217        want_xptr = false
218    endif
219endif
220
221cflags_try = []
222
223### workaround for native compilers, see configure.ac
224if cc.get_argument_syntax() == 'gcc'
225    cflags_try += [
226        '-Wshadow',
227        '-Wpointer-arith',
228        '-Wcast-align',
229        '-Wwrite-strings',
230        '-Wstrict-prototypes',
231        '-Wmissing-prototypes',
232        '-Wno-long-long',
233        '-Wno-format-extra-args',
234    ]
235
236    if host_machine.cpu_family() == 'alpha'
237        cflags_try += '-mieee'
238    endif
239else
240    if host_machine.cpu_family() == 'alpha'
241        cflags_try += '-ieee'
242    elif host_machine.cpu_family() == 'parisc'
243        cflags_try += '-Wp,-H30000'
244    endif
245endif
246
247foreach cf : cflags_try
248    if cc.has_argument(cf)
249        libxml2_cflags += cf
250    endif
251endforeach
252
253# configuration
254#
255# X : done
256# N : not done
257#
258# [X] config.h.in
259# [X] include/libxml/xmlversion.h.in
260# [N] libxml-2.0-uninstalled.pc.in
261# [X] libxml-2.0.pc.in
262# [X] libxml2-config.cmake.in
263# [X] python/setup.py.in
264# [N] xml2-config.in
265
266## config.h
267config_h = configuration_data()
268config_h.set_quoted('PACKAGE_NAME', meson.project_name())
269config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
270config_h.set_quoted('PACKAGE_BIN_DIR', dir_bin)
271config_h.set_quoted('PACKAGE_LIB_DIR', dir_lib)
272config_h.set_quoted('PACKAGE_DATA_DIR', dir_data)
273config_h.set_quoted('LOCALEDIR', dir_locale)
274
275# header files
276xml_check_headers = [
277    'stdint.h',
278    'fcntl.h',
279    'unistd.h',
280    'sys/stat.h',
281    'sys/mman.h',
282    'sys/socket.h',
283    'netinet/in.h',
284    'arpa/inet.h',
285    'netdb.h',
286    'sys/select.h',
287    'poll.h',
288    'sys/time.h',
289    'sys/timeb.h',
290    'dl.h',
291    'dlfcn.h',
292    'glob.h',
293]
294
295foreach header : xml_check_headers
296    if cc.has_header(header)
297        config_h.set10('HAVE_' + header.underscorify().to_upper(), true)
298    endif
299endforeach
300
301# library functions
302xml_check_functions = [
303    # fct             | header
304    ['gettimeofday', 'sys/time.h'],
305    ['ftime', 'sys/timeb.h'],
306    ['stat', 'sys/stat.h'],
307    ['mmap', 'sys/mman.h'],
308    ['munmap', 'sys/mman.h'],
309]
310
311foreach function : xml_check_functions
312    if cc.has_header_symbol(function[1], function[0])
313        config_h.set10('HAVE_' + function[0].to_upper(), true)
314    endif
315endforeach
316
317# library
318
319config_dir = [include_directories('.'), include_directories('include')]
320
321## dependencies
322
323xml_deps = []
324
325### math library
326if sys_windows == false
327    m_dep = cc.find_library('m', required: false)
328    if m_dep.found()
329        xml_deps += m_dep
330    endif
331endif
332
333### thread local storage
334support_tls = true
335if want_tls == true
336    tls_src = '''
337#include <threads.h>
338int main()
339{
340    _Thread_local int v;
341    return 0;
342}
343    '''
344    res = cc.compiles(tls_src, name: '_Thread_local')
345    if res == true
346        config_h.set('XML_THREAD_LOCAL', '_Thread_local')
347    else
348        tls_src = '''
349int main()
350{
351    __thread int v;
352    return 0;
353}
354        '''
355        res = cc.compiles(tls_src, name: '__thread')
356        if res == true
357            config_h.set('XML_THREAD_LOCAL', '__thread')
358        else
359            tls_src = '''
360int main()
361{
362    __declspec(thread) int v;
363    return 0;
364}
365            '''
366            res = cc.compiles(tls_src, name: '__declspec(thread)')
367            if res == true
368                config_h.set('XML_THREAD_LOCAL', '__declspec(thread)')
369            else
370                want_tls = false
371                support_tls = false
372            endif
373        endif
374    endif
375endif
376
377### __attribute__((destructor))
378if cc.has_function_attribute('destructor')
379    config_h.set10('HAVE_ATTRIBUTE_DESTRUCTOR', true)
380    config_h.set('ATTRIBUTE_DESTRUCTOR', '__attribute__((destructor))')
381endif
382
383### DSO support
384if sys_cygwin == true
385    module_extension = '.dll'
386elif sys_windows == true
387    module_extension = '.dll'
388else
389    module_extension = '.so'
390endif
391
392dl_dep = dependency('', required: false)
393if not get_option('minimum')
394    if host_machine.system() != 'windows'
395        if meson.version().version_compare('>=0.62')
396            dl_dep = dependency('dl', required: get_option('modules'))
397        else
398            dl_dep = cc.find_library('dl', required: get_option('modules'))
399        endif
400        if dl_dep.found()
401            config_h.set10('HAVE_DLOPEN', true)
402            xml_deps += dl_dep
403        endif
404    elif get_option('modules').allowed()
405        dl_dep = declare_dependency()
406    endif
407endif
408
409### threads
410threads_dep = dependency('', required: false)
411if not get_option('minimum')
412    if host_machine.system() != 'windows'
413        threads_dep = dependency('threads', required: get_option('threads'))
414        if threads_dep.found()
415            config_h.set10('HAVE_PTHREAD_H', true)
416            xml_deps += threads_dep
417        endif
418    elif get_option('threads').allowed()
419        threads_dep = declare_dependency()
420    endif
421endif
422
423want_thread_alloc = threads_dep.found()
424
425### xmllint shell history
426xmllint_deps = []
427if want_history == true and want_readline == true
428    termlib_lib = ['ncurses', 'curses', 'termcap', 'terminfo', 'termlib']
429
430    foreach tl : termlib_lib
431        termlib_dep = cc.find_library(tl)
432        if (
433            termlib_dep.found()
434            and cc.has_function('tputs', dependencies: termlib_dep)
435        )
436            xmllint_deps += termlib_dep
437            config_h.set10('HAVE_LIB' + tl.underscorify().to_upper(), true)
438            break
439        endif
440    endforeach
441
442    history_dep = dependency('history', required: false)
443    if history_dep.found()
444        xmllint_deps += history_dep
445        config_h.set10('HAVE_LIBHISTORY', true)
446    endif
447
448    readline_dep = dependency('readline', required: false)
449    if readline_dep.found()
450        xmllint_deps += readline_dep
451        config_h.set10('HAVE_LIBREADLINE', true)
452    endif
453endif
454
455### crypto
456if sys_windows == true
457    bcrypt_dep = cc.find_library('bcrypt', required: true)
458    xml_deps += bcrypt_dep
459endif
460
461### inet
462if want_http == true
463    if sys_windows == true
464        ws2_dep = cc.find_library('ws2_32', required: true)
465        xml_deps += ws2_dep
466    else
467        has_in_libc = cc.has_function('gethostbyname')
468        if has_in_libc == false
469            nsl_dep = cc.find_library('nsl', required: true)
470            if nsl_dep.found()
471                has_in_nsl = cc.has_function(
472                    'gethostbyname',
473                    dependencies: nsl_dep,
474                    required: false,
475                )
476                if has_in_nsl == true
477                    xml_deps += nsl_dep
478                endif
479            endif
480        endif
481    endif
482
483    ### socket length
484    socklen_src = '''
485#include <stddef.h>
486#ifdef _WIN32
487  #include <ws2tcpip.h>
488#else
489  #include <sys/socket.h>
490#endif
491int main()
492{
493    (void)getsockopt (1, 1, 1, NULL, (socklen_t *)NULL);
494    return 0;
495}
496    '''
497    res = cc.compiles(socklen_src, name: 'socket length as socklen_t')
498    if res == true
499        config_h.set('XML_SOCKLEN_T', 'socklen_t')
500    else
501        socklen_src = '''
502#include <stddef.h>
503#include <sys/socket.h>
504int main()
505{
506    (void)getsockopt (1, 1, 1, NULL, (size_t *)NULL);
507    return 0;
508}
509        '''
510        res = cc.compiles(socklen_src, name: 'socket length as size_t')
511        if res == true
512            config_h.set('XML_SOCKLEN_T', 'size_t')
513        else
514            socklen_src = '''
515#include <stddef.h>
516#include <sys/socket.h>
517int main()
518{
519    (void)getsockopt (1, 1, 1, NULL, (int *)NULL);
520    return 0;
521}
522            '''
523            res = cc.compiles(socklen_src, name: 'socket length as int')
524            if res == false
525                message('could not determine socket length type, use int')
526            endif
527            config_h.set('XML_SOCKLEN_T', 'int')
528        endif
529    endif
530
531    if want_ipv6 == true
532        ### IPV6 on Windows has been supported since Windows XP SP1 (around 2003)
533        ### see:
534        ### https://learn.microsoft.com/en-us/windows/win32/winsock/ipv6-support-2
535        ### nevertheless, we check it like autotools
536        ipv6_src = '''
537#ifdef _WIN32
538#include <winsock2.h>
539#else
540#include <sys/socket.h>
541#ifdef HAVE_NETDB_H
542#include <netdb.h>
543#endif
544#endif
545int main()
546{
547    struct sockaddr_storage ss;
548    socket(AF_INET6, SOCK_STREAM, 0);
549    getaddrinfo(0, 0, 0, 0);
550    return 0;
551}
552        '''
553        res = cc.compiles(ipv6_src, name: 'support for IPV6')
554        if res == true
555            config_h.set10('SUPPORT_IP6', true)
556        endif
557    endif
558endif
559
560### zlib
561if not get_option('minimum')
562    zlib_dep = dependency('zlib', required: get_option('zlib'))
563else
564    zlib_dep = dependency('', required: false)
565endif
566xml_deps += zlib_dep
567
568### lzma
569if not get_option('minimum')
570    lzma_dep = dependency('liblzma', required: get_option('lzma'))
571else
572    lzma_dep = dependency('', required: false)
573endif
574xml_deps += lzma_dep
575
576### iconv
577if not get_option('minimum')
578    iconv_dep = dependency('iconv', required: get_option('iconv'))
579else
580    iconv_dep = dependency('', required: false)
581endif
582xml_deps += iconv_dep
583
584if not iconv_dep.found() and want_iso8859x == false
585    want_iso8859x = false
586else
587    want_iso8859x = true
588endif
589
590# icu
591icu_dep = dependency('icu-i18n', method: 'pkg-config', required: get_option('icu'))
592if icu_dep.found()
593    def_var = icu_dep.get_variable(pkgconfig: 'DEFS')
594    config_dir += include_directories(def_var)
595    xml_deps += icu_dep
596endif
597
598subdir('include/libxml')
599
600# Set config_h after all subdirs and dependencies have set values
601
602configure_file(output: 'config.h', configuration: config_h)
603
604## libxml2 library
605
606xml_src = [
607    'buf.c',
608    'chvalid.c',
609    'dict.c',
610    'entities.c',
611    'encoding.c',
612    'error.c',
613    'globals.c',
614    'hash.c',
615    'list.c',
616    'parser.c',
617    'parserInternals.c',
618    'SAX2.c',
619    'threads.c',
620    'tree.c',
621    'uri.c',
622    'valid.c',
623    'xmlIO.c',
624    'xmlmemory.c',
625    'xmlstring.c',
626]
627
628xml_opt_src = [
629    [want_c14n, ['c14n.c']],
630    [want_catalog, ['catalog.c']],
631    [want_debug, ['debugXML.c']],
632    [want_html, ['HTMLparser.c', 'HTMLtree.c']],
633    [want_http, ['nanohttp.c']],
634    [want_legacy, ['legacy.c']],
635    [lzma_dep.found(), ['xzlib.c']],
636    [dl_dep.found(), ['xmlmodule.c']],
637    [want_output, ['xmlsave.c']],
638    [want_pattern, ['pattern.c']],
639    [want_reader, ['xmlreader.c']],
640    [want_regexps, ['xmlregexp.c', 'xmlunicode.c']],
641    [want_sax1, ['SAX.c']],
642    [want_schemas, ['relaxng.c', 'xmlschemas.c', 'xmlschemastypes.c']],
643    [want_schemas and not want_xpath, ['xpath.c']],
644    [want_schematron, ['schematron.c']],
645    [want_writer, ['xmlwriter.c']],
646    [want_xinclude, ['xinclude.c']],
647    [want_xpath, ['xpath.c']],
648    [want_xptr, ['xlink.c', 'xpointer.c']],
649]
650
651foreach file : xml_opt_src
652    want = file[0]
653    src = file[1]
654    if want == true
655        if src.length() > 1
656            foreach s : src
657                xml_src += s
658            endforeach
659        else
660            xml_src += src
661        endif
662    endif
663endforeach
664
665xml_lib = library(
666    'xml2',
667    files(xml_src),
668    c_args: libxml2_cflags,
669    dependencies: xml_deps,
670    include_directories: config_dir,
671    install: true,
672    version: meson.project_version(),
673)
674
675dep_inc = include_directories('include')
676xml_dep = declare_dependency(include_directories: dep_inc, link_with: xml_lib, compile_args: dep_args)
677
678meson.override_dependency('libxml-2.0', xml_dep)
679
680## xmllint tool
681
682executable(
683    'xmllint',
684    files('xmllint.c'),
685    dependencies: [xml_dep, xmllint_deps],
686    include_directories: config_dir,
687    install: true,
688)
689
690## xmlcatalog tool
691
692executable(
693    'xmlcatalog',
694    files('xmlcatalog.c'),
695    dependencies: [xml_dep, xmllint_deps],
696    include_directories: config_dir,
697    install: true,
698)
699
700## testdso module
701
702testdso_mod = shared_module(
703    'testdso',
704    files('testdso.c'),
705    build_rpath: get_option('libdir'),
706    include_directories: config_dir,
707    name_prefix: '',
708)
709
710## tests
711
712checks = [
713    'runsuite',
714    'runtest',
715    'runxmlconf',
716# Disabled for now, see #694
717#    'testModule',
718    'testThreads',
719    'testapi',
720    'testchar',
721    'testdict',
722    'testlimits',
723    'testparser',
724    'testrecurse',
725]
726
727foreach check : checks
728    exe = executable(
729        check,
730        files(check + '.c'),
731        dependencies: [threads_dep, xml_dep],
732        include_directories: config_dir,
733    )
734    if check != 'testlimits'
735        test(check, exe, timeout: 0, workdir: meson.current_source_dir())
736    endif
737endforeach
738
739subdir('example')
740subdir('doc')
741
742if want_python == true
743    subdir('python')
744endif
745
746## pc files
747
748pkgmod = import('pkgconfig')
749
750pkgmod.generate(
751    xml_lib,
752    description: 'libXML library version2.',
753    filebase: 'libxml-2.0',
754    name: 'libXML',
755    variables: 'modules=' + dl_dep.found().to_string('1', '0'),
756)
757
758## libxml2-config.cmake file
759
760config_cmake = configuration_data()
761config_cmake.set('LIBXML_MAJOR_VERSION', v_maj)
762config_cmake.set('LIBXML_MINOR_VERSION', v_min)
763config_cmake.set('LIBXML_MICRO_VERSION', v_mic)
764config_cmake.set('VERSION', meson.project_version())
765config_cmake.set('WITH_ICONV', iconv_dep.found().to_int().to_string())
766config_cmake.set('WITH_ICU', icu_dep.found().to_int().to_string())
767config_cmake.set('WITH_LZMA', lzma_dep.found().to_int().to_string())
768config_cmake.set('WITH_MODULES', dl_dep.found().to_int().to_string())
769config_cmake.set('WITH_THREADS', threads_dep.found().to_int().to_string())
770config_cmake.set('WITH_ZLIB', zlib_dep.found().to_int().to_string())
771config_cmake.set('XML_CFLAGS', xml_cflags)
772configure_file(
773    input: 'libxml2-config.cmake.in',
774    output: 'libxml2-config.cmake',
775    configuration: config_cmake,
776    install_dir: dir_lib / 'cmake' / 'libxml2',
777)
778
779install_data(files('libxml.m4'), install_dir: dir_data / 'aclocal')
780
781if support_tls == false
782    message('===============================================================')
783    message('WARNING: Your C compiler appears to not support thread-local')
784    message('storage. Future versions of libxml2 will require this feature')
785    message('for multi-threading.')
786    message('===============================================================\n',
787    )
788endif
789
790# summary
791
792summary(
793    {
794        'OS': host_os,
795        'c14n': want_c14n,
796        'catalog': want_catalog,
797        'debug': want_debug,
798        'history': want_history,
799        'html': want_html,
800        'http': want_http,
801        'iconv': iconv_dep.found(),
802        'icu': icu_dep.found(),
803        'ipv6': want_ipv6,
804        'iso8859x': want_iso8859x,
805        'legacy': want_legacy,
806        'lzma': lzma_dep.found(),
807        'modules': dl_dep.found(),
808        'output': want_output,
809        'pattern': want_pattern,
810        'push': want_push,
811        'python': want_python,
812        'reader': want_reader,
813        'readline': want_readline,
814        'regexps': want_regexps,
815        'sax1': want_sax1,
816        'schemas': want_schemas,
817        'schematron': want_schematron,
818        'threads': threads_dep.found(),
819        'thread-alloc': want_thread_alloc,
820        'tls': want_tls,
821        'tree': want_tree,
822        'valid': want_valid,
823        'writer': want_writer,
824        'xinclude': want_xinclude,
825        'xpath': want_xpath,
826        'xptr': want_xptr,
827        'zlib': zlib_dep.found(),
828    },
829    section: 'Configuration Options Summary:',
830)
831