In the previous post we introduced library dependency checking based on pkg-config --exists LIBRARY command. In this post we go even further and let our script generate also pkg-config based list of cflags and library dependencies from dependencies variable.

First lets change definition of dependencies variable from simple list of library names to list of (library, version) pairs or simple library name as string (same as before). So we can now have deendencies defined this way

dependencies = [
	('glm', '>= 0.9.9.5'),
	('bullet', '>= 2.88'),
	'OGRE-Bites',
]

where we want to check existance of glm >= 0.9.9.5, bullet >= 2.88 libraries and we only care about any OGRE-Bites library version is availaable.

The second change, configure() function defined this way

def configure(env, dependency_list):
	conf = env.Configure(
		custom_tests={'CheckPkgVersion': check_pkg_version})

	for dep in dependency_list:
		pkg = ("%s %s" % dep) if type(dep) == tuple else dep
		if not conf.CheckPkgVersion(pkg):
			print("'%s' library not found" % pkg)
			Exit(1)

	conf_env = conf.Finish()

	pkg_conf = 'pkg-config --cflags --libs ' + ' '.join(  # 1
		map(lambda dep: dep[0] if type(dep) == tuple else dep, dependencies))

	conf_env.ParseConfig(pkg_conf)

	return conf_env

which returns dependencies based auto configured build environment variable. The function check dependencies the same way as before (in build() function), but this time it also create pkg-config based configuration string and calls ParseConfig() environment function (1). In a case of our sample pkg-config generated configuration string looks this way

pkg-config --cflags --libs glm >= 0.9.9.5 bullet >= 2.88 OGRE-Bites

Function configure() is ment to be used this way

dependencies = [
	('glm', '>= 0.9.9.5'),
	('bullet', '>= 2.88'),
	'OGRE-Bites',
]

env = Environment()
env = configure(env, dependencies)

# ...

Full SConstruct sample file listing there

# automated pkg-config based dependencies with version check

# List of pkg-config based library dependencies as (library, version) pair or just package as string (e.g. ('libzmq', '>= 4.3.0') pair or 'libzmq' string).
dependencies = [
	('glm', '>= 0.9.9.5')
]

def build():
	cpp17 = Environment(CXXFLAGS=['-std=c++17'], CCFLAGS=['-Wall', '-g', '-O0'])

	cpp17 = configure(cpp17, dependencies)

	cpp17.Program('main.cpp')


def configure(env, dependency_list):
	conf = env.Configure(
		custom_tests={'CheckPkgVersion': check_pkg_version})

	for dep in dependency_list:
		pkg = ("%s %s" % dep) if type(dep) == tuple else dep
		if not conf.CheckPkgVersion(pkg):
			print("'%s' library not found" % pkg)
			Exit(1)

	conf_env = conf.Finish()

	pkg_conf = 'pkg-config --cflags --libs ' + ' '.join(
		map(lambda dep: dep[0] if type(dep) == tuple else dep, dependencies))

	conf_env.ParseConfig(pkg_conf)

	return conf_env

def check_pkg_version(context, pkg):
	"""custom pkg-config based package version check"""

	context.Message("Checking for '%s' library ... " % pkg)
	res = context.TryAction("pkg-config --exists '%s'" % pkg)[0]
	context.Result(res)
	return res

build()

There is also configure with dependencies github repository sample.