Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions core/modules/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ import state
Import('env')


def standardModule(env, exclude=None, module=None, test_libs=None, unit_tests=None):
def standardModule(env, exclude=None, module=None, test_libs=None, unit_tests=None, bin_cc_targets=None):
"""
Implementation of SConscript logic for "standard" module.

Expand All @@ -95,6 +95,14 @@ def standardModule(env, exclude=None, module=None, test_libs=None, unit_tests=No
then use this parameter to pass list (or space-separated
string) of application names. Can be empty string or list to
not run any unit tests.
@param bin_cc_targets: a dictionary defining whgich binary products (not

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whgich -> which
Not shure targets has a meaning here. The key in dict is a name of the source, not target?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll come up with a better name

the unit tests should be built out of C/C++ files. Each key

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opening parenthesis on previous line is not closed, I guess it should go after "tests".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

of the dictionary is the name of a C/C++ file (with function
'main'). This file will be excluded from the unit tests and
from a list of *.cc files which are complied into a shared
library of the module. And the corresponding value of
the dictionary is a list of libraries which are required to
build the binary.
"""

build_data = DefaultEnvironment()['build_data']
Expand All @@ -104,13 +112,23 @@ def standardModule(env, exclude=None, module=None, test_libs=None, unit_tests=No
module = os.path.basename(os.getcwd())
state.log.debug('standardModule: module = %s path = %s' % (module, path))

# using two optional lists provided by the nmodule to build names of
# *.cc files to be excluded from being used to build module's
# library or unit tests
exclude_cc_files = []
if exclude is not None:
exclude_cc_files = exclude

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exclude_cc_files += exclude, otherwise you are potentially modifying exclude too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. My Python is rusty :-)

if bin_cc_targets is not None:
for f in bin_cc_targets: exclude_cc_files.append(f)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exclude_cc_files += bin_cc_targets.keys()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed


# find all *.cc files and split then in two groups: files for libraries
# and files for test apps
cc_files = set(env.Glob(os.path.join(path, "*.cc"), source=True, strings=True, exclude=exclude))
cc_files = set(env.Glob(os.path.join(path, "*.cc"), source=True, strings=True, exclude=exclude_cc_files))
cc_tests = set(fname for fname in cc_files if os.path.basename(fname).startswith("test"))
# In Python3 order of set iteration is undefined, do manual sorting
cc_objects = sorted(cc_files - cc_tests)
cc_tests = sorted(cc_tests)
state.log.debug('standardModule: exclude_cc_files = ' + str(exclude_cc_files))
state.log.debug('standardModule: cc_objects = ' + str(cc_objects))
state.log.debug('standardModule: cc_tests = ' + str(cc_tests))

Expand Down Expand Up @@ -163,6 +181,18 @@ def standardModule(env, exclude=None, module=None, test_libs=None, unit_tests=No
py_installed = env.Install("$prefix/bin", py_scripts)
build_data['install'] += py_installed

# inject binary targets built of the optionally provided C/C++ files
if bin_cc_targets is not None:
for f,dependencies in bin_cc_targets.items():
source = os.path.basename(str(f))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need basename for source?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. No need. I will eliminate it.

target = source[:-3]
p = env.Program(
target=target,
source=[source],
LIBS=dependencies,
LIBPATH=['$build_dir'] + env['LIBPATH'])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks a bit complicated, I'd think this should work:

for f, dependencies in bin_cc_targets.items():
    p = env.Program(f, LIBS=dependencies, LIBPATH=['$build_dir'] + env['LIBPATH'])

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will give it a try, and if it works then I'll make mods to the code.

build_data['build_targets'] += p
build_data['install'] += env.Install("$prefix/bin", p)

# ================== SConscript logic start here ====================

Expand Down Expand Up @@ -274,6 +304,7 @@ build_data['shlibs'] = shlibs.copy()
build_data['tests'] = []
build_data['unit_tests'] = []
build_data['module_lib'] = defaultdict(lambda: None)
build_data['build_targets'] = []

# store in env so that modules can use it
defEnv = DefaultEnvironment()
Expand All @@ -297,7 +328,6 @@ for mod in all_modules:
standardModule(env, module=mod)

# define targets for shared libs
build_targets = []
for shlib, shopt in shlibs.items():

state.log.debug('defining target for ' + shlib)
Expand All @@ -319,7 +349,7 @@ for shlib, shopt in shlibs.items():
pfx = shopt.get('SHLIBPREFIX', env['SHLIBPREFIX'])
out = env.SharedLibrary(shlib, objects, LIBS=Split(shopt['libs']),
SHLIBPREFIX=pfx, LIBPATH=libPath)
build_targets += out
build_data['build_targets'] += out

# install target
instDir = shopt.get('instDir', 'lib')
Expand All @@ -341,11 +371,11 @@ if utests:
# special builder that checks that unit tests were successful
utests = env.UnitTestCheck('unit-test-check-tag', utests)

build_targets += build_data['tests']
build_data['build_targets'] += build_data['tests']

# define/extend all aliases
state.log.debug("build targets: %s" % map(str, build_targets))
env.Alias("build", build_targets)
state.log.debug("build targets: %s" % map(str, build_data['build_targets']))
env.Alias("build", build_data['build_targets'])
state.log.debug("install targets: %s" % map(str, build_data['install']))
env.Alias("install-notest", build_data['install'])
if utests:
Expand Down
21 changes: 20 additions & 1 deletion core/modules/tests/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,23 @@
Import('env')
Import('standardModule')

standardModule(env, unit_tests="")
import os.path

# Harvest special binary products - files starting with the package's name
# followed by underscore:
#
# tests_<something>.cc
#
# Then make a Scons target for each of those to be returned by the calling
# SConscript. Also add the source file into a list of sources to be excluded
# from the shared library product.

bin_cc_targets = {}
path = "."
for f in env.Glob(os.path.join(path, "tests_*.cc"), source=True, strings=True):
bin_cc_targets[f] = ["qserv_common","util","protobuf","log","log4cxx"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't overdo it. Normally all "test*.cc" files are (unit) tests and we don't want their binaries installed so don't try to make all test_*.cc into true binaries. I'd probably give it different name, not starting with "test".

I believe you can also write:

bin_cc_targets[f] = "qserv_common util protobuf log log4cxx"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should come up with some naming convention for the binaries. Something like: qserv--.cc. For instance my only app module tests should be renamed from "tests_protobuf_version.cc" into "qserv-tests-protobuf.cc". And I agree about avoiding using "test*" in apps names". I just wanted to see if my implementation of standardModule would work. And thanks for the advice to replace a list of dependencies with a string. I'll give it a try.


# Initiate the standard sequence of actions for this module by excluding
# the above discovered binary sources

standardModule(env, bin_cc_targets=bin_cc_targets, unit_tests="")
49 changes: 49 additions & 0 deletions core/modules/tests/tests_protobuf_version.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* LSST Data Management System
* Copyright 2009-2018 AURA/LSST.
*
* This product includes software developed by the
* LSST Project (http://www.lsst.org/).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the LSST License Statement and
* the GNU General Public License along with this program. If not,
* see <http://www.lsstcorp.org/LegalNotices/>.
*/

// System headers

// Third-party headers

// LSST headers
#include "lsst/log/Log.h"

// Qserv headers
#include "proto/worker.pb.h"

namespace {
LOG_LOGGER _log = LOG_GET("lsst.qserv.tests.tests_protobuf_version");
}

int main (int arc, char const* argv[]) {

LOGS(_log, LOG_LVL_INFO, "testing a version of the Protobuf library");

// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.

GOOGLE_PROTOBUF_VERIFY_VERSION;

LOGS(_log, LOG_LVL_INFO, "success");

return 0;
}