diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..36638d7400d041e31f998b768518890c4936d395
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,22 @@
+image: registry.fedoraproject.org/fedora:30
+
+stages:
+  - build
+
+before_script:
+  - dnf install -y gcc meson ninja-build "pkgconfig(gio-2.0)" "pkgconfig(gio-unix-2.0)" "pkgconfig(glib-2.0)"
+
+build:
+  stage: build
+  script:
+    - meson _build .
+    - cd _build
+    - ninja
+    - meson test
+    # Run it again! This previously did not work.
+    - meson test
+  artifacts:
+    when: on_failure
+    name: "libglnx-${CI_COMMIT_REF_NAME}-${CI_JOB_NAME}"
+    paths:
+      - "${CI_PROJECT_DIR}/_build/meson-logs"
diff --git a/README.md b/README.md
index 6589d29be3fdede809a965631a1581fedab8b2c9..3be38d72585e985cfa30077e2ad120f54523b958 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,32 @@ One could also compare this project to gnulib; the salient differences
 there are that at least some of this module is eventually destined for
 inclusion in GLib.
 
+Adding this to your project
+---------------------------
+
+## Meson
+
+First, set up a Git submodule:
+
+```
+git submodule add https://gitlab.gnome.org/GNOME/libglnx subprojects/libglnx
+```
+
+Or a Git [subtree](https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt):
+
+```
+git remote add libglnx https://gitlab.gnome.org/GNOME/libglnx.git
+git fetch libglnx
+git subtree add -P subprojects/libglnx libglnx/master
+```
+
+Then, in your top-level `meson.build`:
+
+```
+libglnx_dep = subproject('libglnx').get_variable('libglnx_dep')
+# now use libglnx_dep in your dependencies
+```
+
 Porting from libgsystem
 -----------------------
 
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..74ee36a37d576f06ef87756ced8dabe1232337b3
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,84 @@
+project('libglnx', 'c')
+
+add_project_arguments('-D_GNU_SOURCE', language: 'c')
+add_project_arguments('-std=gnu99', language: 'c')
+add_project_arguments('-Wno-unused-local-typedefs', language: 'c')
+
+cc = meson.get_compiler('c')
+
+
+check_functions = [
+  'renameat2',
+  'memfd_create',
+  'copy_file_range',
+]
+conf = configuration_data()
+foreach check_function : check_functions
+  have_it = cc.compiles('''
+    #include <sys/types.h>
+    #include <unistd.h>
+    #include <stdio.h>
+    #include <sys/mount.h>
+    #include <fcntl.h>
+    #include <sched.h>
+    #include <linux/loop.h>
+    #include <linux/random.h>
+    #include <sys/mman.h>
+
+    int func (void) {
+      (void) ''' + check_function + ''';
+    }
+    ''',
+    args : '-D_GNU_SOURCE',
+    name : check_function + '() is declared',
+  )
+  conf.set10('HAVE_DECL_' + check_function.underscorify().to_upper(), have_it)
+endforeach
+config_h = configure_file(
+  output : 'config.h',
+  configuration : conf,
+)
+
+libglnx_deps = [
+  dependency('gio-2.0'),
+  dependency('gio-unix-2.0'),
+]
+libglnx_inc = include_directories('.')
+libglnx_sources = [
+  'glnx-backport-autocleanups.h',
+  'glnx-backport-autoptr.h',
+  'glnx-backports.c',
+  'glnx-backports.h',
+  'glnx-console.c',
+  'glnx-console.h',
+  'glnx-dirfd.c',
+  'glnx-dirfd.h',
+  'glnx-errors.c',
+  'glnx-errors.h',
+  'glnx-fdio.c',
+  'glnx-fdio.h',
+  'glnx-local-alloc.c',
+  'glnx-local-alloc.h',
+  'glnx-lockfile.c',
+  'glnx-lockfile.h',
+  'glnx-macros.h',
+  'glnx-missing.h',
+  'glnx-missing-syscall.h',
+  'glnx-shutil.c',
+  'glnx-shutil.h',
+  'glnx-xattrs.c',
+  'glnx-xattrs.h',
+  'libglnx.h',
+]
+
+libglnx = static_library('glnx',
+  libglnx_sources,
+  dependencies : libglnx_deps,
+  include_directories : libglnx_inc,
+  install : false)
+libglnx_dep = declare_dependency(
+  include_directories : libglnx_inc,
+  link_with : libglnx)
+
+subdir('tests')
+
diff --git a/tests/libglnx-testlib.c b/tests/libglnx-testlib.c
new file mode 100644
index 0000000000000000000000000000000000000000..5687d80706989cefdc6786fd05253234f3017a72
--- /dev/null
+++ b/tests/libglnx-testlib.c
@@ -0,0 +1,66 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright 2019 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "libglnx-testlib.h"
+
+#include <errno.h>
+
+#include "libglnx.h"
+
+struct _GLnxTestAutoTempDir
+{
+  gchar *old_cwd;
+  int old_cwd_fd;
+  GLnxTmpDir temp_dir;
+};
+
+_GLnxTestAutoTempDir *
+_glnx_test_auto_temp_dir_enter (void)
+{
+  GError *error = NULL;
+  _GLnxTestAutoTempDir *ret = g_new0 (_GLnxTestAutoTempDir, 1);
+
+  glnx_mkdtemp ("glnx-test-XXXXXX", 0700, &ret->temp_dir, &error);
+  g_assert_no_error (error);
+
+  /* just for better diagnostics */
+  ret->old_cwd = g_get_current_dir ();
+
+  glnx_opendirat (-1, ".", TRUE, &ret->old_cwd_fd, &error);
+  g_assert_no_error (error);
+
+  if (fchdir (ret->temp_dir.fd) != 0)
+    g_error ("fchdir(<fd for \"%s\">): %s", ret->temp_dir.path, g_strerror (errno));
+
+  return ret;
+}
+
+void
+_glnx_test_auto_temp_dir_leave (_GLnxTestAutoTempDir *dir)
+{
+  GError *error = NULL;
+
+  if (fchdir (dir->old_cwd_fd) != 0)
+    g_error ("fchdir(<fd for \"%s\">): %s", dir->old_cwd, g_strerror (errno));
+
+  glnx_tmpdir_delete (&dir->temp_dir, NULL, &error);
+  g_assert_no_error (error);
+}
diff --git a/tests/libglnx-testlib.h b/tests/libglnx-testlib.h
index ee750e499c0d08eddbe4f189d58a527f98d5ae97..0d3a07511f428a6ca3d9584ee36af1b2091dc6a6 100644
--- a/tests/libglnx-testlib.h
+++ b/tests/libglnx-testlib.h
@@ -1,6 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
  *
  * Copyright (C) 2017 Red Hat, Inc.
+ * Copyright 2019 Collabora Ltd.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,6 +21,10 @@
 
 #pragma once
 
+#include <glib.h>
+
+#include "glnx-backport-autoptr.h"
+
 typedef GError _GLnxTestAutoError;
 static inline void
 _glnx_test_auto_error_cleanup (_GLnxTestAutoError *autoerror)
@@ -32,3 +37,12 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(_GLnxTestAutoError, _glnx_test_auto_error_cleanup)
 #define _GLNX_TEST_DECLARE_ERROR(local_error, error)      \
   g_autoptr(_GLnxTestAutoError) local_error = NULL; \
   GError **error = &local_error
+
+typedef struct _GLnxTestAutoTempDir _GLnxTestAutoTempDir;
+
+_GLnxTestAutoTempDir *_glnx_test_auto_temp_dir_enter (void);
+void _glnx_test_auto_temp_dir_leave (_GLnxTestAutoTempDir *dir);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(_GLnxTestAutoTempDir, _glnx_test_auto_temp_dir_leave);
+
+#define _GLNX_TEST_SCOPED_TEMP_DIR \
+  g_autoptr(_GLnxTestAutoTempDir) temp_dir = _glnx_test_auto_temp_dir_enter ()
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..de141c5a0e9f956f19037f4e41373710e692200b
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,23 @@
+
+test_names = [
+  'errors',
+  'fdio',
+  'macros',
+  'shutil',
+  'xattrs',
+]
+
+foreach test_name : test_names
+  exe = executable(test_name,
+    [
+      'libglnx-testlib.c',
+      'libglnx-testlib.h',
+      'test-libglnx-' + test_name + '.c',
+    ],
+    dependencies: [
+      libglnx_dep,
+      libglnx_deps,
+    ],
+  )
+  test(test_name, exe)
+endforeach
diff --git a/tests/test-libglnx-fdio.c b/tests/test-libglnx-fdio.c
index 81636e59cb74ee91056eb15a3c41c99ff54c624b..84ebb14d679c870c396a6da08f4725192950af3f 100644
--- a/tests/test-libglnx-fdio.c
+++ b/tests/test-libglnx-fdio.c
@@ -237,6 +237,7 @@ test_filecopy (void)
 
 int main (int argc, char **argv)
 {
+  _GLNX_TEST_SCOPED_TEMP_DIR;
   int ret;
 
   g_test_init (&argc, &argv, NULL);