diff --git a/.qmake.conf b/.qmake.conf
new file mode 100644
index 0000000000000000000000000000000000000000..716685d2ad2769eee4df0af499f253ead3318bfb
--- /dev/null
+++ b/.qmake.conf
@@ -0,0 +1,6 @@
+# The qmake generated module files belong into our build/qmake dir
+MODULE_QMAKE_OUTDIR = $$shadowed($$PWD/build/qmake)
+QMAKEPATH += $$PWD/build/qmake $$MODULE_QMAKE_OUTDIR
+load(qt_build_config)
+
+MODULE_VERSION = 5.2.0
diff --git a/README b/README
index 6b120d018bf23697227513cde905cdd3f6b7755a..dfb29b523ecb5e72534b24127720580460339a3b 100644
--- a/README
+++ b/README
@@ -15,7 +15,7 @@ This is a prototype of allowing embedding Chromium/Blink into Qt.
 (2) (Re-)generating the ninja build files after changing a gyp file:
 
     * set the CHROMIUM_SRC_DIR environment variable to point to /path/to/src/
-    * Run gyp_blinq
+    * Simply run qmake in the top-level directory
 
 (3) build with ninja -C out/Release (or out/Debug depending on the needs)
 
diff --git a/blinq.pro b/blinq.pro
new file mode 100644
index 0000000000000000000000000000000000000000..cb7c33b7efd2275a0f224be9bfafdc7c35518025
--- /dev/null
+++ b/blinq.pro
@@ -0,0 +1,8 @@
+TEMPLATE = subdirs
+
+CONFIG += ordered
+
+SUBDIRS = lib \ # Contains a dummy lib target that is used to generate qt_generated.gypi
+          build \ # This is where we use the generated qt_generated.gypi and run gyp
+          example \
+
diff --git a/build/build.pro b/build/build.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2798233717a6fc66fcf44d8a115b069761b2c4d7
--- /dev/null
+++ b/build/build.pro
@@ -0,0 +1,25 @@
+# This .pro file serves a dual purpose:
+# 1) invoking gyp through the gyp_blinq script, which in turn makes use of the generated gypi include files
+# 2) produce a Makefile that will run ninja, and take care of actually building everything.
+
+TEMPLATE = aux
+
+# Fetched from environment for now
+CHROMIUM_SRC_DIR = $$(CHROMIUM_SRC_DIR)
+isEmpty(CHROMIUM_SRC_DIR):error("please set CHOMIUM_SRC_DIR")
+
+message(Running Gyp...)
+GYP_OUTPUT = $$system(./gyp_blinq)
+message($$GYP_OUTPUT)
+
+ninja.target = ninja
+# FIXME: Don't hardcode Release... might be tricky to get right if we also don't want to hardcode 'out'
+ninja.commands = $$CHROMIUM_SRC_DIR/../depot_tools/ninja -C $$BLINQ_ROOT/out/Release
+ninja.depends: qmake
+QMAKE_EXTRA_TARGETS += ninja
+
+build_pass:build_all:default_target.target = all
+else: default_target.target = first
+default_target.depends = ninja
+
+QMAKE_EXTRA_TARGETS += default_target
diff --git a/gyp_blinq b/build/gyp_blinq
similarity index 74%
rename from gyp_blinq
rename to build/gyp_blinq
index e98e3e8abc80774848ea550744a25ab9627b09f6..b22e759b7d6f652ad27c14834c0a908a71ea792d 100755
--- a/gyp_blinq
+++ b/build/gyp_blinq
@@ -5,16 +5,12 @@ import os
 import subprocess
 import sys
 
-#FIXME(pierre): mandatory until we have a git submodule, for now we can't guess where the chromium checkout lives.
-if "CHROMIUM_SRC_DIR" not in os.environ:
-  print "Please set the environment variable CHROMIUM_SRC_DIR to point to your checkout of chromium's 'src' directory"
-  sys.exit(1)
-
-chrome_src = os.path.abspath(os.environ.get('CHROMIUM_SRC_DIR'));
-script_dir = os.path.abspath(os.path.join(chrome_src, 'build'));
+chrome_src = os.path.abspath(os.environ.get('CHROMIUM_SRC_DIR')) # null-checked in build.pro
+script_dir = os.path.abspath(os.path.join(chrome_src, 'build'))
 if not os.path.isdir(script_dir):
   print script_dir + " is not a valid directory"
   sys.exit(1)
+root_dir = os.path.abspath(os.path.join(os.getcwd(), os.pardir))
 
 sys.path.insert(0, script_dir)
 import gyp_helper
@@ -60,7 +56,7 @@ def additional_include_files(args=[]):
 
 # TODO: later we probably want to hook that up with qmake to allow shadow builds. (Might not play nice with the rest of chromium though)
 def get_output_dir():
-  outdir = os.path.join(os.getcwd(), "out") # Hardcode for now
+  outdir = os.path.join(root_dir, "out") # Hardcode for now
   if not os.path.isdir(outdir):
     os.mkdir(outdir)
 
@@ -80,7 +76,7 @@ if __name__ == '__main__':
       break
 
   if not gyp_file_specified:
-      args.append(os.path.join(os.getcwd(), 'blinq.gyp'))
+      args.append(os.path.join(root_dir, 'blinq.gyp'))
 
   args.extend(['-I' + i for i in additional_include_files(args)])
 
@@ -96,27 +92,7 @@ if __name__ == '__main__':
   if sys.platform not in ('darwin',):
     args.append('--no-circular-check')
 
-  # QMake detection
-  proc = subprocess.Popen(["qmake", "-query"], stdout=subprocess.PIPE)
-  out = proc.communicate()[0].split('\n')
-  for line in out:
-    if line.startswith("QT_INSTALL_LIBS"):
-      qt_libs = line.split(':')[1]
-    elif line.startswith("QT_INSTALL_HEADERS"):
-      qt_headers = line.split(':')[1]
-    elif line.startswith("QMAKE_SPEC"):
-      qmake_spec = line.split(':')[1]
-    elif line.startswith("QT_VERSION"):
-      qt_version = line.split(':')[1]
-      # FIXME: remove this check once it's move up in the pro file
-      if not qt_version.startswith('5'):
-        print "Qt 5 is a minimum requirement for Blinq"
-        sys.exit(5)
-
   args.extend(['-D', 'use_aura=1'])
-  args.extend(['-D', 'qt_libdir=' + qt_libs])
-  args.extend(['-D', 'qt_headers=' + qt_headers])
-  args.extend(['-D', 'qmake_spec=' + qmake_spec])
   args.extend(['-D', 'webkit_src_dir=' + chrome_src + '/third_party/WebKit'])
   args.extend(["--depth=" + chrome_src])
   args.extend(['-D', 'chromium_src_dir=' + chrome_src])
diff --git a/build/qmake/mkspecs/features/default_pre.prf b/build/qmake/mkspecs/features/default_pre.prf
new file mode 100644
index 0000000000000000000000000000000000000000..c54908efd691c96c62acf2e35beab77945fbab9b
--- /dev/null
+++ b/build/qmake/mkspecs/features/default_pre.prf
@@ -0,0 +1,4 @@
+# Resolve root directories for sources
+BLINQ_ROOT = $$replace(PWD, /build/qmake/mkspecs/features$,)
+
+# TODO: Build dir logic
diff --git a/build/qmake/mkspecs/features/functions.prf b/build/qmake/mkspecs/features/functions.prf
new file mode 100644
index 0000000000000000000000000000000000000000..8d0df1a4e5b70dfc78274dce4bfeb1165c5b71d2
--- /dev/null
+++ b/build/qmake/mkspecs/features/functions.prf
@@ -0,0 +1,9 @@
+# Map to the correct target type for gyp
+defineReplace(toGypTargetType) {
+  equals(TEMPLATE, "app"):return("executable")
+  equals(TEMPLATE, "lib") {
+    CONFIG(static): return("static_library")
+    return("shared_library")
+  }
+  return("none")
+}
diff --git a/build/qmake/mkspecs/features/gypi_gen.prf b/build/qmake/mkspecs/features/gypi_gen.prf
new file mode 100644
index 0000000000000000000000000000000000000000..ee32c3661d0b04df31bc2f56e8dc4230ec362c1b
--- /dev/null
+++ b/build/qmake/mkspecs/features/gypi_gen.prf
@@ -0,0 +1,48 @@
+# This file is loaded after the dummy .pro and all the default_post ran.
+# This is the right point to extract the variables we're interested in and generate
+# the .gyp file that we'll use later on when running gyp
+
+load(functions)
+
+GYPI_FILE = $$replace(_PRO_FILE_, .pro$, .gyp)
+
+TARGET_TYPE = $$toGypTargetType()
+
+GYPI_CONTENTS =  "{" \
+                 "  'targets': [" \
+                 "  {" \
+                 "    'target_name': '$$TARGET'," \
+                 "    'type': '$$TARGET_TYPE'," \
+                 "    'includes': [" \
+                 "      '../blinq.gypi'," \
+                 "    ]," \
+                 "    'ldflags': ["
+for (lib, LIBS): GYPI_CONTENTS += "      '$$lib',"
+!isEmpty(QMAKE_RPATHDIR): GYPI_CONTENTS += "      '$$QMAKE_RPATH$$QMAKE_RPATHDIR',"
+
+GYPI_CONTENTS += "    ],"
+
+!isEmpty(DEFINES) {
+  GYPI_CONTENTS += "    'defines': ["
+  for (define, DEFINES): GYPI_CONTENTS += "      '$$define',"
+  GYPI_CONTENTS += "    ],"
+}
+GYPI_CONTENTS += "    'sources': ["
+for (sourcefile, SOURCES): GYPI_CONTENTS += "      '$$sourcefile',"
+for (headerfile, HEADERS): GYPI_CONTENTS += "      '$$headerfile',"
+GYPI_CONTENTS += "    ],"
+!isEmpty(INCLUDEPATH) {
+  GYPI_CONTENTS += "    'include_dirs': ["
+  for (path, INCLUDEPATH): GYPI_CONTENTS += "      '$$path',"
+  GYPI_CONTENTS += "    ],"
+}
+GYPI_CONTENTS += "  }," \
+                 "  ]," \
+                 "}"
+
+write_file($$GYPI_FILE, GYPI_CONTENTS)
+
+# The generated Makefile shouldn't build anything by itself, just re-run qmake if necessary
+TEMPLATE = aux
+SOURCES =
+HEADERS =
diff --git a/lib/lib.gyp b/lib/lib.gyp
deleted file mode 100644
index fee379de28e627efa899324acd803bd1b9a1e7a7..0000000000000000000000000000000000000000
--- a/lib/lib.gyp
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-  'targets': [
-  {
-    'target_name': 'blinq',
-      'type': 'shared_library',
-      'includes': [
-        '../blinq.gypi',
-      ],
-      'sources': [
-        'blinqpage.cpp',
-        'blinqpage.h',
-      ],
-      'libraries': [
-        '-lQt5Core',
-        '-lQt5Gui',
-      ],
-      'ldflags': [
-        '-L<(qt_libdir)',
-        '-Wl,-rpath,<(qt_libdir)',
-      ],
-      'cflags': [
-        '-DQT_NO_KEYWORDS',
-      ],
-      'include_dirs': [
-        '<(qt_headers)',
-        '<(qt_headers)/QtCore',
-        '<(qt_headers)/QtGui',
-        '<(qt_headers)/QtGui/5.2.0/QtGui',
-      ],
-  },
-    ],
-}
diff --git a/lib/lib.pro b/lib/lib.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e79923236e5f6c517fac23057896a9d3b550e8bb
--- /dev/null
+++ b/lib/lib.pro
@@ -0,0 +1,20 @@
+# This is a dummy .pro file used to extract some aspects of the used configuration and feed them to gyp
+# We want the gyp generation step to happen after all the other config steps. For that we need to prepend
+# our gypi_gen.prf feature to the CONFIG variable since it is processed backwards
+CONFIG = gypi_gen $$CONFIG
+
+TEMPLATE = lib
+
+TARGET = blinq
+
+# Defining keywords such as 'signal' clashes with the chromium code base.
+DEFINES += QT_NO_KEYWORDS
+
+QT += gui-private
+
+SOURCES = \
+        blinqpage.cpp
+
+HEADERS = \
+        blinqpage.h
+
diff --git a/process/process.gyp b/process/process.gyp
deleted file mode 100644
index c055c2e9f0411750ed5fdbf6d2a9297e2ea50a5f..0000000000000000000000000000000000000000
--- a/process/process.gyp
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  'targets': [
-  {
-    'target_name': 'blinq_process',
-      'type': 'executable',
-      'includes': [
-        '../blinq.gypi',
-      ],
-      'sources': [
-        'main.cpp',
-      ],
-  },
-    ],
-}
diff --git a/process/process.pro b/process/process.pro
new file mode 100644
index 0000000000000000000000000000000000000000..efb517a5fc7b63c27f78c157b6e310c1c142ff35
--- /dev/null
+++ b/process/process.pro
@@ -0,0 +1,11 @@
+# This is a dummy .pro file used to extract some aspects of the used configuration and feed them to gyp
+# We want the gyp generation step to happen after all the other config steps. For that we need to prepend
+# our gypi_gen.prf feature to the CONFIG variable since it is processed backwards
+CONFIG = gypi_gen $$CONFIG
+
+TARGET = blinq_process
+TEMPLATE = app
+
+QT -= gui core
+
+SOURCES = main.cpp