Repository: tschoonj/xraylib (language: python)

Issue:
Add meson support
For the Python and Fortran bindings. Should make building with MSVC a breeze...

<!-- Edit the body of your new issue then click the ✓ "Create Issue" button in the top right of the editor. The first line will be the issue title. Assignees and Labels follow after a blank line. Leave an empty line before beginning the body of the issue. -->


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9a5a8368..2e8caf7a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,10 +11,53 @@ on:
       - master
 
 jobs:
+  visual-studio:
+    timeout-minutes: 60
+    runs-on: windows-latest
+    strategy:
+      matrix:
+        python-version: [ '3.6', '3.7', '3.8', '3.9']
+        compiler:
+          - cl
+          - clang-cl
+        # don't know why but cl.exe does not like the Cython generated code with python < 3.8
+        include:
+          - numpy: enabled
+          - python-version: 3.6
+            numpy: disabled
+            compiler: cl
+          - python-version: 3.7
+            numpy: disabled
+            compiler: cl
+    name: Visual Studio with ${{matrix.compiler}} and Python ${{ matrix.python-version }}
+    steps:
+    - uses: actions/checkout@v2
+    - uses: conda-incubator/setup-miniconda@v2
+      with:
+        auto-update-conda: true
+        channels: conda-forge
+        python-version: ${{ matrix.python-version }}
+    - name: Install meson, ninja, numpy and cython
+      run: |
+        conda install -q -y meson ninja numpy cython swig
+    - uses: ilammy/msvc-dev-cmd@v1
+    - name: Build with meson
+      run: |
+        meson setup builddir --buildtype=release -Dpython=python -Dpython-bindings=enabled -Dpython-numpy-bindings=${{ matrix.numpy }}
+        ninja -C builddir
+        ninja -C builddir test
+        ninja -C builddir dist
+      env:
+        CC: ${{ matrix.compiler }}
+        CXX: ${{ matrix.compiler }}
+
   msys2:
     timeout-minutes: 60
     strategy:
       matrix:
+        buildsystem:
+          - autotools
+          - meson
         cc:
           - clang
           - gcc
@@ -52,6 +95,7 @@ jobs:
           mingw-w64-x86_64-curl
           mingw-w64-x86_64-cython
           mingw-w64-x86_64-python3-numpy
+          mingw-w64-x86_64-meson
           automake
           autoconf
           make
@@ -59,7 +103,41 @@ jobs:
           wget
           tar
     - uses: actions/checkout@v2
-    - name: Build and test with Autotools
+    - name: Primary build and test with Meson
+      if: matrix.buildsystem == 'meson'
+      run: |
+        set -ex
+
+        mkdir build
+        cd build
+        meson -Dpython-bindings=enabled -Dpython-numpy-bindings=enabled ..
+        ninja
+        ninja test
+        ninja dist
+
+        set +ex
+      env:
+        CC: ${{matrix.cc}}
+        CXX: ${{matrix.cxx}}
+    - name: Secondary build with Autotools 
+      if: matrix.buildsystem == 'meson'
+      run: |
+        set -ex
+        cd build/meson-dist/
+        TARBALL=$(ls *.tar.xz)
+        tar xfJ $TARBALL
+        cd ${TARBALL%.tar.xz}
+        autoreconf -fi
+        ./configure --enable-python --disable-ruby
+        make
+        set +ex
+      env:
+        CC: ${{matrix.cc}}
+        CXX: ${{matrix.cxx}}
+        CYTHON: cython
+        PYTHON: python3
+    - name: Primary build and test with Autotools
+      if: matrix.buildsystem == 'autotools'
       run: |
         set -ex
 
@@ -83,7 +161,7 @@ jobs:
         ./configure --enable-python --enable-python-numpy PYTHON=python3 --disable-ruby
         make
         make check
-        make distclean
+        make dist
 
         set +ex
       env:
@@ -91,20 +169,42 @@ jobs:
         CXX: ${{matrix.cxx}}
         CYTHON: cython
         PYTHON: python3
+    
+    - name: Secondary build with Meson
+      if: matrix.buildsystem == 'autotools'
+      run: |
+        set -ex
+        export PATH=${HOME}/.local/bin:${PATH}
+        TARBALL=$(ls *.tar.gz)
+        tar xfz $TARBALL
+        cd ${TARBALL%.tar.gz}
+        mkdir build-meson
+        cd build-meson
+        meson -Dpython-bindings=enabled -Dpython-numpy-bindings=enabled ..
+        ninja
+        set +ex
+      env:
+        CC: ${{matrix.cc}}
+        CXX: ${{matrix.cxx}}
 
   macos:
     timeout-minutes: 60
     runs-on: macos-latest
     strategy:
       matrix:
+        buildsystem:
+          - autotools
+          - meson
         compiler:
           - llvm
           - gcc
         include:
+          - ldflags: ""
           # at least some versions of clang cannot compile php bindings
           - compiler: llvm
             cc: /usr/local/opt/llvm/bin/clang
             cxx: /usr/local/opt/llvm/bin/clang++
+            ldflags: -L/usr/local/opt/llvm/lib
           - compiler: gcc
             cc: gcc-10
             cxx: g++-10
@@ -117,7 +217,7 @@ jobs:
         brew uninstall -f bazel bazelisk
         brew update
         brew upgrade
-        brew install git autoconf automake libtool pkg-config python ${{ matrix.compiler }} swig ruby fpc lua perl php@7.4 bash numpy
+        brew install git autoconf automake libtool pkg-config python ${{ matrix.compiler }} swig ruby@2.6 fpc lua perl php@7.4 bash numpy meson ninja
         set +ex
       env:
         HOMEBREW_CURL_RETRIES: 5
@@ -126,13 +226,48 @@ jobs:
       run: |
         /usr/local/bin/pip3 install Cython
 
+    - name: Primary Build and test with Meson
+      if: matrix.buildsystem == 'meson'
+      run: |
+        set -ex
+
+        mkdir build
+        cd build
+        meson -Dpython=/usr/local/bin/python3 -Dpython-bindings=enabled -Dpython-numpy-bindings=enabled ..
+        ninja
+        ninja test
+        ninja dist
+
+        set +ex
+      env:
+        CC: ${{matrix.cc}}
+        CXX: ${{matrix.cxx}}
+        LDFLAGS: ${{matrix.ldflags}}
+    - name: Secondary build with Autotools 
+      if: matrix.buildsystem == 'meson'
+      run: |
+        set -ex
+        cd build/meson-dist/
+        TARBALL=$(ls *.tar.xz)
+        tar xfJ $TARBALL
+        cd ${TARBALL%.tar.xz}
+        autoreconf -fi
+        ./configure --enable-python SHELL=${SHELL} PYTHON=/usr/local/bin/python3
+        make
+        make check
+        set +ex
+      env:
+        CC: ${{matrix.cc}}
+        CXX: ${{matrix.cxx}}
+        SHELL: /usr/local/bin/bash
     - name: Build with Autotools
+      if: matrix.buildsystem == 'autotools'
       run: |
         set -ex
         autoreconf -fi
 
         # Build without python
-        ./configure --disable-python --disable-python-numpy --disable-ruby --enable-perl --enable-lua --enable-pascal --disable-java --enable-php --enable-ruby PHP=/usr/local/opt/php@7.4/bin/php PHP_CONFIG=/usr/local/opt/php@7.4/bin/php-config SHELL=${SHELL}
+        ./configure --disable-python --disable-python-numpy --disable-ruby --enable-perl --enable-lua --enable-pascal --disable-java --enable-php --enable-ruby PHP=/usr/local/opt/php@7.4/bin/php PHP_CONFIG=/usr/local/opt/php@7.4/bin/php-config SHELL=${SHELL} RUBY=/usr/local/opt/ruby@2.6/bin/ruby
         make
         make check || (cat perl/tests/test-suite.log && exit 1)
         make distclean
@@ -157,7 +292,7 @@ jobs:
 
         # Run make distcheck
         ./configure
-        make distcheck SHELL=${SHELL} PYTHON=${XRL_PYTHON3}
+        make distcheck SHELL=${SHELL} PYTHON=${XRL_PYTHON3} RUBY=/usr/local/opt/ruby@2.6/bin/ruby
 
         set +ex
       env:
@@ -165,21 +300,61 @@ jobs:
         CXX: ${{matrix.cxx}}
         SHELL: /usr/local/bin/bash
         XRL_PYTHON3: /usr/local/bin/python3
+    - name: Secondary build with Meson
+      if: matrix.buildsystem == 'autotools'
+      run: |
+        set -ex
+        export PATH=${HOME}/.local/bin:${PATH}
+        TARBALL=$(ls *.tar.gz)
+        tar xfz $TARBALL
+        cd ${TARBALL%.tar.gz}
+        mkdir build-meson
+        cd build-meson
+        meson -Dpython-bindings=enabled -Dpython-numpy-bindings=enabled ..
+        ninja
+        set +ex
+      env:
+        CC: ${{matrix.cc}}
+        CXX: ${{matrix.cxx}}
+        LDFLAGS: ${{matrix.ldflags}}
 
   linux:
     timeout-minutes: 60
     strategy:
+      fail-fast: false
       matrix:
         image: 
           - ubuntu:bionic
           - ubuntu:focal
+          - ubuntu:devel
           - debian:buster
+          - debian:sid
           - centos:7
           - centos:8
           - fedora:latest
+          - fedora:rawhide
         cc:
           - clang
           - gcc
+        buildsystem:
+          - autotools
+          - meson
+        exclude:
+          - image: ubuntu:bionic
+            buildsystem: meson
+          - image: ubuntu:focal
+            buildsystem: meson
+          - image: debian:buster
+            buildsystem: meson
+          - image: centos:7
+            buildsystem: meson
+          - image: centos:8
+            buildsystem: meson
+          - image: fedora:latest
+            buildsystem: meson
+          # autoconf doesnt like the rawhide shell
+          - image: fedora:rawhide
+            buildsystem: autotools
         include:
           # at least some versions of clang cannot compile php bindings
           - cython: cython
@@ -218,8 +393,12 @@ jobs:
             lua: /usr/bin/lua5.3
           - image: ubuntu:focal
             lua: /usr/bin/lua5.3
+          - image: ubuntu:devel
+            lua: /usr/bin/lua5.3
           - image: debian:buster
             lua: /usr/bin/lua5.3
+          - image: debian:sid
+            lua: /usr/bin/lua5.3
           - image: centos:7
             lua: /usr/bin/lua
           - image: centos:8
@@ -232,6 +411,21 @@ jobs:
       image: ${{ matrix.image }}
 
     steps:
+    - name: Install Git
+      if: startsWith(matrix.image, 'ubuntu') || startsWith(matrix.image, 'debian')
+      run: |
+        set -ex
+        apt-get --yes --force-yes update
+        apt-get --yes --force-yes install git
+        set +ex
+      env:
+        DEBIAN_FRONTEND: noninteractive
+    - name: Install Git
+      if: startsWith(matrix.image, 'centos') || startsWith(matrix.image, 'fedora')
+      run: |
+        set -ex
+        yum install -y git
+        set +ex
     - uses: actions/checkout@v2
     - name: Install ubuntu dependencies
       if: startsWith(matrix.image, 'ubuntu') || startsWith(matrix.image, 'debian')
@@ -243,6 +437,14 @@ jobs:
         set +ex
       env:
         DEBIAN_FRONTEND: noninteractive
+    - name: Install ubuntu dependencies Meson and Ninja
+      if: matrix.buildsystem == 'meson' && (startsWith(matrix.image, 'ubuntu') || startsWith(matrix.image, 'debian'))
+      run: |
+        set -ex
+        apt-get --yes --force-yes install meson ninja-build
+        set +ex
+      env:
+        DEBIAN_FRONTEND: noninteractive
     - name: Activate CentOS 8 PowerTools and EPEL repo
       if: matrix.image == 'centos:8'
       run: |
@@ -269,7 +471,30 @@ jobs:
         javac -version
         which javac
         set +ex
-    - name: Build and test
+    - name: Install RHEL dependencies Meson and Ninja
+      if: matrix.buildsystem == 'meson' && (startsWith(matrix.image, 'centos') || startsWith(matrix.image, 'fedora'))
+      run: |
+        set -ex
+        yum install -y meson ninja-build
+        set +ex
+    - name: Build and test with Meson
+      if: matrix.buildsystem == 'meson'
+      run: |
+        set -ex
+        mkdir build
+        cd build
+        meson -Dpython-bindings=enabled -Dpython-numpy-bindings=enabled ..
+        ninja
+        ninja test
+        ninja dist
+        set +ex
+      env:
+        CYTHON: ${{matrix.cython}}
+        CC: ${{matrix.cc}}
+        CXX: ${{matrix.cxx}}
+        LIBS: ${{matrix.libs}}
+    - name: Build and test with Autotools
+      if: matrix.buildsystem == 'autotools'
       run: |
         set -ex
         autoreconf -fi
diff --git a/.gitignore b/.gitignore
index d15f74af..44992fc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,3 +71,4 @@ xraylib.spec
 *ppu
 *.pyc
 .DS_Store
+meson-build
diff --git a/.lgtm.yml b/.lgtm.yml
index 23c00739..03616984 100644
--- a/.lgtm.yml
+++ b/.lgtm.yml
@@ -1,5 +1,9 @@
 extraction:
   cpp:
+    configure:
+      command:
+        - autoreconf -fi
+        - ./configure
     index:
       build_command:
         - make
diff --git a/Makefile.am b/Makefile.am
index 5222c707..31a110a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,6 +39,6 @@ windows:
 	$(MAKE) -C windows windows
 
 
-EXTRA_DIST = xraylib.spec.in Changelog
+EXTRA_DIST = xraylib.spec.in Changelog meson.build meson_options.txt
 
 .PHONY: windows 
diff --git a/fortran/Makefile.am b/fortran/Makefile.am
index 8b37cc98..49778263 100644
--- a/fortran/Makefile.am
+++ b/fortran/Makefile.am
@@ -32,4 +32,4 @@ SUBDIRS = tests
 
 endif
 
-EXTRA_DIST = xraylib_wrap_generated.F90
+EXTRA_DIST = xraylib_wrap_generated.F90 meson.build install_fortran_mod.py
diff --git a/fortran/install_fortran_mod.py b/fortran/install_fortran_mod.py
new file mode 100755
index 00000000..5eda7cbc
--- /dev/null
+++ b/fortran/install_fortran_mod.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+
+# taken from https://thispointer.com/python-how-to-get-list-of-files-in-directory-and-sub-directories/
+
+import os
+import sys
+import shutil
+
+'''
+    For the given path, get the List of all files in the directory tree 
+'''
+def getListOfFiles(dirName):
+    # create a list of file and sub directories 
+    # names in the given directory 
+    listOfFile = os.listdir(dirName)
+    allFiles = list()
+    # Iterate over all the entries
+    for entry in listOfFile:
+        # Create full path
+        fullPath = os.path.join(dirName, entry)
+        # If entry is a directory then get the list of files in this directory 
+        if os.path.isdir(fullPath):
+            allFiles = allFiles + getListOfFiles(fullPath)
+        else:
+            allFiles.append(fullPath)
+                
+    return allFiles
+
+build_root = os.environ['MESON_BUILD_ROOT']
+install_destdir_prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX']
+files = getListOfFiles(build_root)
+files = list(filter(lambda file: os.path.basename(file) == 'xraylib.mod', files))
+if not files:
+    sys.exit('xraylib.mod was not found!')
+
+shutil.copy(files[0], os.path.join(install_destdir_prefix, 'include', 'xraylib'))
+
+
+
diff --git a/fortran/meson.build b/fortran/meson.build
new file mode 100644
index 00000000..770b9aef
--- /dev/null
+++ b/fortran/meson.build
@@ -0,0 +1,25 @@
+xraylib_fortran_lib = library(
+    'xrlf03',
+    files('xraylib_wrap.F90'),
+    version: version,
+    darwin_versions: darwin_versions,
+    dependencies: [xraylib_lib_dep],
+    install: true,
+    include_directories: include_directories('.'),
+    link_language: 'fortran',
+)
+
+xraylib_fortran_lib_dep = declare_dependency(link_with: xraylib_fortran_lib, include_directories: ['.'])
+
+pkgconfig.generate(
+    xraylib_fortran_lib,
+    name: 'xraylib Fortran 2003 bindings',
+    description: 'xraylib provides access to x-ray related physical data',
+    filebase: 'libxrlf03',
+    subdirs: ['xraylib'],
+)
+
+# need to setup post install script for mod file
+meson.add_install_script('install_fortran_mod.py')
+
+subdir('tests')
diff --git a/include/Makefile.am b/include/Makefile.am
index be2fbb48..469cd712 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -11,3 +11,5 @@ xraylibinclude_HEADERS = 	xraylib.h \
 				xraylib-radionuclides.h \
 				xraylib-error.h \
 				xraylib-deprecated.h
+
+EXTRA_DIST = meson.build
diff --git a/include/meson.build b/include/meson.build
new file mode 100644
index 00000000..2c7d2d14
--- /dev/null
+++ b/include/meson.build
@@ -0,0 +1,17 @@
+xraylib_headers = files(
+    'xraylib.h',
+    'xraylib-lines.h',
+    'xraylib-shells.h',
+    'xraylib-parser.h',
+    'xraylib-auger.h',
+    'xraylib-defs.h',
+    'xraylib-crystal-diffraction.h',
+    'xraylib-nist-compounds.h',
+    'xraylib-radionuclides.h',
+    'xraylib-error.h',
+    'xraylib-deprecated.h',
+)
+
+install_headers(xraylib_headers, subdir: 'xraylib')
+
+include_source_dir = meson.current_source_dir()
\ No newline at end of file
diff --git a/java/Makefile.am b/java/Makefile.am
index 8c7b962c..e523101e 100644
--- a/java/Makefile.am
+++ b/java/Makefile.am
@@ -43,7 +43,7 @@ xraylib-$(VERSION).jar: xraylib.dat $(java_source)
 	$(srcdir)/gradlew build sourcesJar javadocJar -x test
 
 xraylib.dat: prdata_java$(EXEEXT)
-	$(AM_V_GEN) XRAYLIB_DIR=${top_srcdir} $(WINE) ./prdata_java$(EXEEXT)
+	$(AM_V_GEN) $(WINE) ./prdata_java$(EXEEXT) ${top_srcdir}
 
 clean-local:
 	rm -rf xraylib-$(VERSION).jar xraylib-$(VERSION)-javadoc.jar xraylib-$(VERSION)-sources.jar  xraylib.dat com build .gradle META-INF xrlexample7.class prdata_java.dSYM
diff --git a/java/pr_data_java.c b/java/pr_data_java.c
index f8047c59..0360d39a 100644
--- a/java/pr_data_java.c
+++ b/java/pr_data_java.c
@@ -31,6 +31,7 @@ extern double Auger_Transition_Individual[ZMAX+1][AUGERNUM];
 #define NAME_PER_LINE 4
 
 void XRayInit(void);
+void XRayInitFromPath(char *path);
 FILE *f;
 
 #define PR_MATD(ARRNAME) \
@@ -950,7 +951,7 @@ void print_intvec(int arrmax, int *arr)
 }
 
 
-int main(void)
+int main(int argc, char *argv[])
 {
 
   int i,j;
@@ -969,7 +970,13 @@ int main(void)
   double kev2angst = KEV2ANGST;
   double r_e = R_E;
 
+  if (argc != 2) {
+	  fprintf(stderr, "Invoke this program with the xraylib source root directory as only argument!\n");
+	  return 1;
+  }
+
   XRayInit();
+  XRayInitFromPath(argv[1]);
 
   f = fopen(OUTFILE, "w");
   if(f == NULL) {
diff --git a/meson.build b/meson.build
new file mode 100644
index 00000000..7673251d
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,185 @@
+project('xraylib',
+    ['c'],
+    meson_version: '>= 0.56.0',
+    version:'4.0.0',
+    license: 'BSD')
+
+# versioning stuff -> maintain compatibility with libtool!
+# # a) If binary compatibility has been broken (eg removed or changed interfaces)
+# #    change to C+1:0:0.
+# # b) If interfaces have been changed or added, but binary compatibility has
+# #    been preserved, change to C+1:0:A+1
+# # c) If the interface is the same as the previous version, change to C:R+1:A
+lib_current = 12
+lib_revision = 0
+lib_age = 1
+
+version = '@0@.@1@.@2@'.format((lib_current - lib_age), lib_age, lib_revision)
+
+current = lib_current + 1
+interface_age = lib_revision
+darwin_versions = [current, '@0@.@1@'.format(current , interface_age)]
+
+host_system = host_machine.system()
+
+cc = meson.get_compiler('c')
+
+# Use these instead of meson.source_root() and meson.build_root() in subdirectories.
+# source_root() and build_root() are not useful, if this is a subproject.
+project_source_root = meson.current_source_dir()
+project_build_root = meson.current_build_dir()
+
+# Configuration data
+config_h_data = configuration_data()
+config_h_data.set_quoted('PACKAGE_TARNAME', meson.project_name())
+config_h_data.set_quoted('PACKAGE_VERSION', meson.project_version())
+config_h_data.set_quoted('VERSION', meson.project_version())
+
+funcs = [
+  'strdup',
+  '_strdup',
+]
+
+if host_system != 'windows'
+    funcs += ['strndup']
+endif
+
+foreach f : funcs
+  if cc.has_function(f)
+    define = 'HAVE_' + f.underscorify().to_upper()
+    config_h_data.set(define, 1)
+  endif
+endforeach
+
+
+special_funcs = []
+
+if host_system == 'windows'
+  special_funcs += ['_vscprintf', '_scprintf', '_vsnprintf', '_snprintf']
+else
+  special_funcs += ['vasprintf', 'asprintf']
+endif
+
+legacy_stdio_dep =  cc.find_library('legacy_stdio_definitions', required: false)
+
+foreach f : special_funcs
+  if not cc.has_function(f, args : '-D_GNU_SOURCE', dependencies: legacy_stdio_dep)
+    error('Required function ' + f + ' not found on this platform')
+  endif
+endforeach
+
+# Detect and set symbol visibility
+if get_option('default_library') != 'static'
+  if host_system == 'windows' or host_system == 'cygwin'
+    if cc.get_id() == 'msvc' or cc.get_id() == 'clang-cl'
+      config_h_data.set('XRL_EXTERN', '__declspec(dllexport) extern')
+    elif cc.has_argument('-fvisibility=hidden')
+      config_h_data.set('XRL_EXTERN', '__attribute__((visibility("default"))) __declspec(dllexport) extern')
+    endif
+  elif cc.has_argument('-fvisibility=hidden')
+    config_h_data.set('XRL_EXTERN', '__attribute__((visibility("default"))) extern')
+  endif
+endif
+ 
+if cc.get_id() not in ['msvc', 'clang-cl'] and cc.has_header('complex.h')
+  config_h_data.set('HAVE_COMPLEX_H', true)
+endif
+
+configure_file(output : 'config.h', configuration : config_h_data)
+
+m_dep = cc.find_library('m', required : false)
+xraylib_build_dep = [m_dep]
+
+pkgconfig = import('pkgconfig')
+
+subdir('include')
+subdir('src')
+subdir('tests')
+
+if not (get_option('python-bindings').disabled() and get_option('python-numpy-bindings').disabled())
+    pymod = import('python')
+    python = pymod.find_installation(get_option('python'), required: false, modules: ['numpy',])
+
+    if not python.found() or python.language_version().version_compare('< 3.6')
+        if get_option('python-bindings').enabled() or get_option('python-numpy-bindings').enabled()
+            error('No suitable Python installation was found. The Python bindings cannot not be built')
+        else
+            warning('No suitable Python installation was found. The Python bindings cannot not be built')
+        endif
+    else
+        python_dep = python.dependency()
+        subdir('python')
+    endif
+endif
+
+if not get_option('fortran-bindings').disabled()
+    if add_languages('fortran', required: get_option('fortran-bindings'), native: false)
+    	fc = meson.get_compiler('fortran')
+
+    	c_loc_test = '''
+MODULE f2003_test
+USE, INTRINSIC ::ISO_C_BINDING
+
+TYPE, BIND(C) :: test_C
+	INTEGER (C_INT) :: arrayLen
+	TYPE (C_PTR) :: cpointer
+ENDTYPE
+
+TYPE :: test_F
+	INTEGER (C_INT), DIMENSION(:), POINTER :: fpointer
+ENDTYPE
+
+INTERFACE
+	FUNCTION foo (bar,morebar) BIND(C,NAME='foo')
+		USE, INTRINSIC ::ISO_C_BINDING
+		IMPLICIT NONE
+		REAL (KIND=C_DOUBLE) :: foo
+		INTEGER (KIND=C_INT), INTENT(IN) :: bar
+		REAL (KIND=C_DOUBLE), INTENT(IN) :: morebar
+	ENDFUNCTION foo
+	FUNCTION strlen(s) BIND(C,NAME='strlen')
+		USE, INTRINSIC ::ISO_C_BINDING
+		IMPLICIT NONE
+		CHARACTER (KIND=C_CHAR),DIMENSION(*) :: s
+		INTEGER (C_SIZE_T) :: strlen
+	ENDFUNCTION
+ENDINTERFACE
+ENDMODULE f2003_test
+PROGRAM f2003_main
+USE f2003_test
+IMPLICIT NONE
+
+CHARACTER (LEN=10,KIND=C_CHAR) :: string = C_CHAR_'123456789' // C_NULL_CHAR
+TYPE (test_C) :: tester_C
+TYPE (test_F) :: tester_F
+
+
+
+IF (strlen(string) /= 9) THEN
+	CALL EXIT(1)
+ELSE
+	CALL EXIT(0)
+ENDIF
+
+!next line should produce a compile-time error when using g95
+CALL C_F_POINTER(tester_C%cpointer,tester_F%fpointer,[tester_C%arrayLen])
+
+!use c_loc
+tester_C%cpointer = C_LOC(tester_F%fpointer(1))
+
+
+ENDPROGRAM f2003_main
+'''
+
+    	if fc.compiles(c_loc_test)
+            subdir('fortran')
+        else
+            if get_option('fortran-bindings').enabled()
+    		    error('The Fortran compiler does not support the required 2003 standard features')
+            else
+    		    warning('The Fortran compiler does not support the required 2003 standard features')
+            endif
+    	endif
+
+    endif
+endif
\ No newline at end of file
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 00000000..f4a74db5
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,6 @@
+option('fortran-bindings', type: 'feature', value: 'auto', description: 'Build Fortran 2003 bindings')
+option('python-bindings', type: 'feature', value: 'auto', description: 'Build classic Python bindings')
+option('python-numpy-bindings', type: 'feature', value: 'auto', description: 'Build numpy Python bindings')
+option('swig', type : 'string', value : 'swig', description: 'Path to swig executable')
+option('python', type : 'string', value : 'python3', description: 'Python interpreter to compile bindings for')
+option('cython', type : 'string', value : 'cython', description: 'Cython to use for generating C glue code')
diff --git a/python/Makefile.am b/python/Makefile.am
index 6555ce64..3f345e1a 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -60,4 +60,4 @@ if ENABLE_PYTHON
 SUBDIRS = tests
 endif
 
-EXTRA_DIST = xraylib_np_c.pxd xraylib_np.pyx pyfragments.swg
+EXTRA_DIST = xraylib_np_c.pxd xraylib_np.pyx pyfragments.swg meson.build
diff --git a/python/meson.build b/python/meson.build
new file mode 100644
index 00000000..90f68b54
--- /dev/null
+++ b/python/meson.build
@@ -0,0 +1,88 @@
+# get numpy header location
+numpy_include_script = '''
+import numpy
+print(numpy.get_include())
+'''
+
+rv = run_command(get_option('python'), '-c', numpy_include_script,)
+if rv.returncode() != 0
+  error('Could not retrieve numpy include location. Please check that numpy has been installed.')
+endif
+numpy_header_location = rv.stdout().strip()
+
+python_error_flags = [
+  '-Wno-error=cpp',
+  '-Wno-error=attributes',
+  '-Wno-error=deprecated-declarations',
+  '-Wno-error=unreachable-code',
+  '-Wno-error=ignored-optimization-argument',
+]
+
+python_error_flags = cc.get_supported_arguments(python_error_flags)
+
+pydir = meson.current_build_dir()
+
+if not get_option('python-bindings').disabled()
+    swig = find_program(get_option('swig'), 'swig', required : get_option('python-bindings'))
+    if swig.found()
+        xraylib_wrap_c = custom_target('xraylib_wrap_c',
+            output : ['xraylib_wrap.c', 'xraylib.py'],
+            input : swig_interface,
+            depend_files : xraylib_headers,
+            command : [
+                swig,
+                '-DVERSION=\'@0@\''.format(meson.project_version()),
+                '-includeall',
+                '-I@0@'.format(include_source_dir),
+                '-I@0@'.format(src_source_dir),
+                '-o', '@OUTPUT0@',
+                '-python',
+                '-py3',
+                '@INPUT@',
+                ],
+            install_dir: [false, python.get_install_dir(pure: false)],
+            install: true,
+        )
+        xraylib_ext = python.extension_module('_xraylib', xraylib_wrap_c[0],
+            dependencies : [python_dep, xraylib_lib_dep],
+            include_directories: extra_include_dirs,
+            install: true,
+            install_dir: python.get_install_dir(pure: false),
+            c_args: core_c_args + ['-I' + numpy_header_location] + python_error_flags,
+        )
+        subdir('tests')
+    endif
+
+endif
+
+if not get_option('python-numpy-bindings').disabled()
+    cython = find_program(get_option('cython'), 'cython', 'cython3', 'cython-3', 'cython' + python.language_version(), 'cython-' + python.language_version(), required : false)
+    deps = [python_dep, xraylib_lib_dep]
+    # lld-link doesnt find the openmp import libraries
+    if cc.get_id() != 'clang-cl'
+      deps += [dependency('openmp', language: 'c', required: false)]
+    endif
+    if cython.found()
+        xraylib_np_c = custom_target('xraylib_np_c',
+            output : 'xraylib_np.c',
+            input : 'xraylib_np.pyx',
+            depend_files : 'xraylib_np_c.pxd',
+            command : [
+                cython,
+                '-X',
+                'language_level=3,boundscheck=False,wraparound=False,cdivision=True',
+                '@INPUT@',
+                '-o',
+                '@OUTPUT@',
+            ],
+        )
+        xraylib_np_ext = python.extension_module('xraylib_np', xraylib_np_c,
+            dependencies : deps,
+            include_directories: extra_include_dirs,
+            install: true,
+            install_dir: python.get_install_dir(pure: false),
+            c_args: core_c_args + ['-I' + numpy_header_location] + python_error_flags,
+        )
+
+    endif
+endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 9213db95..e57d741a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -107,14 +107,14 @@ nodist_libxrl_la_SOURCES = xrayglob_inline.c
 libxrl_la_LDFLAGS=-version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ $(LDFLAGS_LIBXRL)
 libxrl_la_LIBADD = $(LIBM)
 
-EXTRA_DIST = xraylib.i
+EXTRA_DIST = xraylib.i meson.build
 
 all:
 
 #$(EXEEXT) is necessary to allow compilation in cygwin
 #wine is necessary when cross-compiling
 xrayglob_inline.c: prdata$(EXEEXT)
-	$(AM_V_GEN) XRAYLIB_DIR=${top_srcdir} $(WINE) ./prdata$(EXEEXT)
+	$(AM_V_GEN) $(WINE) ./prdata$(EXEEXT) ${top_srcdir} xrayglob_inline.c
 
 clean-local:
 	rm -rf xrayglob_inline.c xraylib.mod prdata.dSYM libxrl-$(LIB_CURRENT_MINUS_AGE).def
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 00000000..ccc95c38
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,141 @@
+core_c_args = [
+  '-DHAVE_CONFIG_H',
+  '-D_GNU_SOURCE',
+]
+
+xraylib_error_flags = [
+  '-Werror=implicit-function-declaration',
+  '-Werror=implicit',
+  '-Werror=unused-function',
+  '-Werror=parentheses',
+  '-Werror=unused-result',
+]
+
+# clang-cl really doesnt like posix functions like strerror etc
+if cc.get_id() != 'clang-cl'
+    xraylib_error_flags += [
+        '-Werror=deprecated',
+        '-Werror=deprecated-declarations',
+    ]
+endif
+
+xraylib_error_flags = cc.get_supported_arguments(xraylib_error_flags)
+
+extra_include_dirs = include_directories('..', '.', '../include',)
+
+shared_sources = files(
+    'atomicweight.c',
+    'auger_trans.c',
+    'coskron.c',
+    'cross_sections.c',
+    'crystal_diffraction.c',
+    'fi.c',
+    'fii.c',
+    'fluor_yield.c',
+    'radrate.c',
+    'scattering.c',
+    'splint.c',
+    'splint.h',
+    'xraylib-aux.c',
+    'xraylib-aux.h',
+    'xraylib-error.c',
+    'xraylib-error-private.h',
+    'xrayglob.h',
+    'xrayvars.c',
+    'xrayvars.h',
+    'xrf_cross_sections_aux-private.h',
+    'xrf_cross_sections_aux-private.c',
+)
+
+libprdata_sources = shared_sources + files(
+    'xrayglob.c',
+    'xrayfiles.c',
+)
+
+prdata_sources = files(
+    'pr_data.c'
+)
+
+prdata_lib = static_library(
+  'prdata',
+  libprdata_sources,
+  dependencies: xraylib_build_dep,
+  c_args: core_c_args + xraylib_error_flags,
+  include_directories: extra_include_dirs,
+  native: true,
+)
+
+prdata_lib_dep = declare_dependency(
+  link_with: prdata_lib,
+  include_directories: extra_include_dirs,
+  dependencies: xraylib_build_dep,
+)
+
+prdata_exec = executable(
+  'prdata',
+  prdata_sources,
+  dependencies: prdata_lib_dep,
+  c_args: core_c_args + xraylib_error_flags,
+  native: true,
+)
+
+xrayglob_inline = custom_target(
+    'xrayglob_inline.c',
+    output: ['xrayglob_inline.c'],
+    command: [prdata_exec, project_source_root, '@OUTPUT@']
+)
+
+libxrl_sources = shared_sources + [xrayglob_inline] + files(
+    'atomiclevelwidth.c',
+    'comptonprofiles.c',
+    'cs_barns.c',
+    'cs_cp.c',
+    'cs_line.c',
+    'densities.c',
+    'edges.c',
+    'fluor_lines.c',
+    'jump.c',
+    'kissel_pe.c',
+    'polarized.c',
+    'refractive_indices.c',
+    'xrayfiles_inline.c',
+    'xraylib-deprecated-private.h',
+    'xraylib-nist-compounds.c',
+    'xraylib-nist-compounds-internal.h',
+    'xraylib-parser.c',
+    'xraylib-radionuclides-internal.h',
+    'xraylib-radionuclides.c',
+    'xrf_cross_sections_aux.h',
+    'xrf_cross_sections_aux.c',
+)
+
+xraylib_lib = library(
+  'xrl',
+  libxrl_sources,
+  version: version,
+  darwin_versions: darwin_versions,
+  dependencies: xraylib_build_dep,
+  install: true,
+  c_args: core_c_args + xraylib_error_flags,
+  gnu_symbol_visibility: 'hidden',
+  include_directories: extra_include_dirs,
+)
+
+xraylib_lib_dep = declare_dependency(
+  link_with: xraylib_lib,
+  include_directories: extra_include_dirs,
+  dependencies: xraylib_build_dep,
+)
+
+swig_interface = files('xraylib.i')
+
+src_source_dir = meson.current_source_dir()
+src_build_dir = meson.current_build_dir()
+
+pkgconfig.generate(
+    xraylib_lib,
+    name: 'xraylib',
+    description: 'xraylib provides access to x-ray related physical data',
+    filebase: 'libxrl',
+    subdirs: ['xraylib'],
+)
diff --git a/src/pr_data.c b/src/pr_data.c
index 3656af83..9ae750a0 100644
--- a/src/pr_data.c
+++ b/src/pr_data.c
@@ -28,6 +28,8 @@ extern double Auger_Transition_Individual[ZMAX+1][AUGERNUM];
 #define NAME_PER_LINE 4
 
 void XRayInit(void);
+void XRayInitFromPath(char *path);
+
 FILE *filePtr;
 
 #define PR_CUBED(DIM1MAX, DIM2MAX, DIM3MAX, ARRNAME) \
@@ -1090,16 +1092,22 @@ void print_intvec(int arrmax, int *arr)
 }
 
 
-int main(void)
+int main(int argc, char *argv[])
 {
 
   int i,j,k, Z;
   Crystal_Struct* crystal;
   Crystal_Atom* atom;
 
+  if (argc != 3) {
+	  fprintf(stderr, "Invoke this program with the xraylib source root directory as first argument and destination file as second argument!\n");
+	  return 1;
+  }
+
   XRayInit();
+  XRayInitFromPath(argv[1]);
 
-  filePtr = fopen(OUTFILE, "w");
+  filePtr = fopen(argv[2], "w");
   if(filePtr == NULL) {
     perror("file open");
   }
diff --git a/src/xrayfiles.c b/src/xrayfiles.c
index 1f480a3b..cc6471d0 100644
--- a/src/xrayfiles.c
+++ b/src/xrayfiles.c
@@ -31,15 +31,17 @@ double Auger_Transition_Individual[ZMAX+1][AUGERNUM];
 
 void ArrayInit(void);
 
+void XRayInit(void) {
 
-void XRayInit(void)
+}
+
+void XRayInitFromPath(char *path)
 {
 
   char XRayLibDir[MAXFILENAMESIZE];
   FILE *fp;
   char file_name[MAXFILENAMESIZE];
   char shell_name[25], line_name[25], trans_name[5], auger_name[10];
-  char *path;
   int Z, iE;
   int i, ex, stat;
   int shell, line, trans, auger;
@@ -62,17 +64,17 @@ void XRayInit(void)
 
   /* Define XRayLibDir */
 
-  if ((path = getenv("XRAYLIB_DIR")) == NULL) {
-    if ((path = getenv("HOME")) == NULL) {
-      fprintf(stderr, "Environment variables XRAYLIB_DIR and HOME not defined");
+  if (path == NULL) {
+      fprintf(stderr, "path cannot be NULL!");
       exit(1);
-    }
-    strcpy(XRayLibDir, path);
-    strcat(XRayLibDir, "/.xraylib/data/");
   }
   else {
     strcpy(XRayLibDir, path);
+#ifdef _WIN32
+    strcat(XRayLibDir, "\\data\\");
+#else
     strcat(XRayLibDir, "/data/");
+ #endif
   }
 
   ArrayInit();


Test patch:
diff --git a/fortran/tests/Makefile.am b/fortran/tests/Makefile.am
index 5b9cce63..43191209 100644
--- a/fortran/tests/Makefile.am
+++ b/fortran/tests/Makefile.am
@@ -66,3 +66,5 @@ clean-local:
 	rm -f libtest.mod
 
 endif
+
+EXTRA_DIST = meson.build
\ No newline at end of file
diff --git a/fortran/tests/meson.build b/fortran/tests/meson.build
new file mode 100644
index 00000000..43b0e926
--- /dev/null
+++ b/fortran/tests/meson.build
@@ -0,0 +1,25 @@
+test_lib = static_library(
+    'unittest',
+    files('libtest.f90'),
+)
+
+test_lib_dep = declare_dependency(
+    link_with: test_lib,
+)
+
+tests = [
+	'atomiclevelwidth',
+	'atomicweight',
+	'auger',
+	'compoundparser',
+	'comptonprofiles',
+	'crystal_diffraction',
+	'refractive_indices',
+	'nist-compounds',
+	'radionuclides',
+]
+
+foreach _test : tests
+  _test_exec = executable(_test, files('test-' + _test + '.f90'), dependencies: [xraylib_fortran_lib_dep, test_lib_dep])
+  test('fortran-' + _test, _test_exec, timeout: 30)
+endforeach
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
index b0aa9f4e..e747ec28 100644
--- a/python/tests/Makefile.am
+++ b/python/tests/Makefile.am
@@ -19,3 +19,4 @@ dist_check_SCRIPTS = \
 endif
 
 TESTS = $(dist_check_SCRIPTS)
+EXTRA_DIST = meson.build
diff --git a/python/tests/meson.build b/python/tests/meson.build
new file mode 100644
index 00000000..d4811f50
--- /dev/null
+++ b/python/tests/meson.build
@@ -0,0 +1,26 @@
+tests = [
+	'atomiclevelwidth',
+	'atomicweight',
+	'auger',
+	'compoundparser',
+	'comptonprofiles',
+	'crystal_diffraction',
+	'nist-compounds',
+	'radionuclides',
+]
+
+test_env = environment()
+test_env.prepend('PYTHONPATH', pydir)
+if host_system == 'windows'
+    test_env.prepend('PATH', src_build_dir)
+endif
+
+foreach _test : tests
+  test('python-' + _test,
+    python,
+    args : files('test-' + _test + '.py'),
+    env : test_env,
+    timeout: 10,
+    depends: [xraylib_ext]
+  )
+endforeach
\ No newline at end of file
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c59f4e01..979bd027 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -129,6 +129,8 @@ test_nist_compounds_LDADD = ../src/libxrl.la
 test_radionuclides_SOURCES = test-radionuclides.c
 test_radionuclides_LDADD = ../src/libxrl.la
 
+EXTRA_DIST = meson.build
+
 clean-local:
 	rm -rf test-error.dSYM
 
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 00000000..4f79b8d1
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,34 @@
+tests = [
+	'atomiclevelwidth',
+	'atomicweight',
+	'auger',
+	'compoundparser',
+	'comptonprofiles',
+	'coskron',
+	'cross_sections',
+	'crystal_diffraction',
+	'cs_barns',
+	'cs_cp',
+	'cs_line',
+	'densities',
+	'edges',
+	'fi',
+	'fii',
+	'fluor_lines',
+	'fluor_yield',
+	'jump',
+	'kissel_pe',
+	'polarized',
+	'radrate',
+	'refractive_indices',
+	'scattering',
+	'nist-compounds',
+	'radionuclides',
+	'error',
+	'version',
+]
+
+foreach _test : tests
+  _test_exec = executable(_test, files('test-' + _test + '.c'), c_args: core_c_args, dependencies: [xraylib_lib_dep, ])
+  test(_test, _test_exec, timeout: 30)
+endforeach
\ No newline at end of file
diff --git a/tests/test-crystal_diffraction.c b/tests/test-crystal_diffraction.c
index ff3dd61e..f125b1bb 100644
--- a/tests/test-crystal_diffraction.c
+++ b/tests/test-crystal_diffraction.c
@@ -155,11 +155,11 @@ int main(int argc, char **argv) {
 	current_ncrystals = nCrystals;
 
 	for (i = 0 ; i < CRYSTALARRAY_MAX ; i++) {
-		char *name = NULL;
-		assert(asprintf(&name, "Diamond copy %d", i) > 0);
+		char name[100];
+		assert(snprintf(name, 100, "Diamond copy %d", i) > 0);
 		cs_copy = Crystal_MakeCopy(cs, &error);
 		free(cs_copy->name);
-		cs_copy->name = name;
+		cs_copy->name = xrl_strdup(name);
 		rv = Crystal_AddCrystal(cs_copy, NULL, &error);
 		if (current_ncrystals < CRYSTALARRAY_MAX) {
 			assert(rv == 1);
@@ -211,25 +211,25 @@ int main(int argc, char **argv) {
 	xrl_clear_error(&error);
 
 	/* Q_scattering_amplitude */
-	tmp = Q_scattering_amplitude(cs, 10.0, 1, 1, 1, M_PI/4.0, &error);
+	tmp = Q_scattering_amplitude(cs, 10.0, 1, 1, 1, PI/4.0, &error);
 	assert(error == NULL);
 	assert(fabs(tmp - 0.19184445408324474) < 1E-6);
 
-	tmp = Q_scattering_amplitude(NULL, 10.0, 1, 1, 1, M_PI/4, &error);
+	tmp = Q_scattering_amplitude(NULL, 10.0, 1, 1, 1, PI/4, &error);
 	assert(tmp == 0.0);
 	assert(error != NULL);
 	assert(error->code == XRL_ERROR_INVALID_ARGUMENT);
 	assert(strcmp(error->message, CRYSTAL_NULL) == 0);
 	xrl_clear_error(&error);
 
-	tmp = Q_scattering_amplitude(cs, -10.0, 1, 1, 1, M_PI/4, &error);
+	tmp = Q_scattering_amplitude(cs, -10.0, 1, 1, 1, PI/4, &error);
 	assert(tmp == 0.0);
 	assert(error != NULL);
 	assert(error->code == XRL_ERROR_INVALID_ARGUMENT);
 	assert(strcmp(error->message, NEGATIVE_ENERGY) == 0);
 	xrl_clear_error(&error);
 
-	tmp = Q_scattering_amplitude(cs, 10.0, 0, 0, 0, M_PI/4, &error);
+	tmp = Q_scattering_amplitude(cs, 10.0, 0, 0, 0, PI/4, &error);
 	assert(tmp == 0.0);
 	assert(error == NULL);