diff options
71 files changed, 2606 insertions, 2214 deletions
diff --git a/.gitignore b/.gitignore index 3fc5557322..3a3e97fdb9 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ lib/*/lib/*.lib lib/qtscript-bytearray/*.cc *.vscode +compile_commands.json
\ No newline at end of file diff --git a/src/SConscript b/SConscript index 3a538db5d8..1754889cc5 100644 --- a/src/SConscript +++ b/SConscript @@ -35,23 +35,23 @@ flags = build.flags # both mixxx and mixxx-test. mixxx_lib = env.StaticLibrary('libmixxx', [source for source in sources - if str(source) != 'main.cpp']) + if str(source) != 'src/main.cpp']) # mixxx.qrc must not be bundled into libmixxx.a since the linker will not link # it into the resulting binary unless it is on the link command-line explicitly # (it has no link-time symbols that are needed by anything in Mixxx). -mixxx_qrc = env.StaticObject(env.Qrc5('qrc_mixxx', '#res/mixxx.qrc')) +mixxx_qrc = env.StaticObject(env.Qrc5('res/mixxx.cc', 'res/mixxx.qrc')) # libmixxx.a needs to precede all other libraries so that symbols it requires # end up in the linker's list of unresolved symbols before other libraries are # searched for symbols. env.Prepend(LIBS=mixxx_lib) -mixxx_main = env.StaticObject('main.cpp') +mixxx_main = env.StaticObject('src/main.cpp') #Tell SCons to build Mixxx #========================= if build.platform_is_windows: dist_dir = 'dist%s' % build.bitwidth # Populate the stuff that changes in the .rc file - fo = open(File('#src/mixxx.rc.include').abspath, "w") + fo = open(File('src/mixxx.rc.include').abspath, "w") str_list = [] str_list.append('#define VER_FILEVERSION ') @@ -79,7 +79,7 @@ if build.platform_is_windows: fo.write(''.join(str_list)) fo.close() - mixxx_rc = env.RES('#src/mixxx.rc') + mixxx_rc = env.RES('src/mixxx.rc') mixxx_bin = env.Program('mixxx', [mixxx_main, mixxx_qrc, mixxx_rc], LINKCOM = [env['LINKCOM'], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1']) @@ -104,25 +104,25 @@ else: test_bin = None def define_test_targets(default=False): global test_bin - test_files = Glob('test/*.cpp', strings=True) + test_files = Glob('src/test/*.cpp', strings=True) test_env = env.Clone() - test_env.Append(CPPPATH="#lib/gtest-1.7.0/include") - test_env.Append(CPPPATH="#lib/gmock-1.7.0/include") - test_env.Append(CPPPATH="#lib/benchmark/include") - test_files = [test_env.StaticObject(filename) - if filename !='main.cpp' else filename - for filename in test_files] - test_sources = test_files - test_env.Append(LIBPATH="#lib/gtest-1.7.0/lib") + test_env.Append(CPPPATH="lib/gtest-1.7.0/include") + test_env.Append(LIBPATH="lib/gtest-1.7.0") test_env.Append(LIBS=['gtest']) - test_env.Append(LIBPATH="#lib/gmock-1.7.0/lib") + test_env.Append(CPPPATH="lib/gmock-1.7.0/include") + test_env.Append(LIBPATH="lib/gmock-1.7.0") test_env.Append(LIBS=['gmock']) - test_env.Append(LIBPATH="#lib/benchmark/lib") + test_env.Append(CPPPATH="lib/benchmark/include") + test_env.Append(LIBPATH="lib/benchmark") test_env.Append(LIBS=['benchmark']) + test_files = [test_env.StaticObject(filename) + if filename !='src/test/main.cpp' else filename + for filename in test_files] + if build.platform_is_windows: # For SHGetValueA in Google's benchmark library. test_env.Append(LIBS=['Shlwapi']) @@ -138,10 +138,10 @@ def define_test_targets(default=False): # Currently both executables are built with /subsystem:windows # and the console is attached manually test_bin = test_env.Program( - 'mixxx-test', [test_sources, mixxx_qrc, mixxx_rc], + 'mixxx-test', [test_files, mixxx_qrc, mixxx_rc], LINKCOM = [env['LINKCOM'], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1']) else: - test_bin = test_env.Program('mixxx-test', [test_sources, mixxx_qrc]) + test_bin = test_env.Program('mixxx-test', [test_files, mixxx_qrc]) if not build.platform_is_windows: copy_test_bin = Command("../mixxx-test", test_bin, Copy("$TARGET", "$SOURCE")) @@ -533,16 +533,29 @@ if build.platform_is_windows: #env.Alias('mixxx', icon) env.Alias('mixxx', binary) + binaries_to_codesign = [binary, dlls, vamp_plugins] + # imageformats DLL if imgfmtdll_files: imageformats_dll = env.Install(os.path.join(base_dist_dir, "imageformats"), imgfmtdll_files) + binaries_to_codesign.append(imageformats_dll) env.Alias('mixxx', imageformats_dll) # QSQLite DLL if sqldll_files: sql_dlls = env.Install(os.path.join(base_dist_dir, "sqldrivers"), sqldll_files) + binaries_to_codesign.append(sql_dlls) env.Alias('mixxx', sql_dlls) + if 'sign' in COMMAND_LINE_TARGETS: + codesign_subject_name = SCons.ARGUMENTS.get('windows_codesign_subject_name', '') + if not codesign_subject_name: + raise Exception('Code-signing was requested but windows_codesign_subject_name was not provided.') + codesign = env.SignTool( + 'Mixxx_signtool', + binaries_to_codesign, + SUBJECT_NAME=codesign_subject_name) + env.Alias('sign', codesign) def BuildRelease(target, source, env): print("==== Mixxx Post-Build Checks ====") @@ -560,8 +573,8 @@ def BuildRelease(target, source, env): package_version = construct_version(build, mixxx_version, branch_name, vcs_revision) arch = "x64" if build.machine_is_64bit else "x86" - exe_name = '%s-%s-%s.msi' % (package_name, package_version, arch) - print(exe_name) + msi_name = '%s-%s-%s.msi' % (package_name, package_version, arch) + print(msi_name) print("Top line of README, check version:") if build.platform_is_windows: os.system('for /l %l in (1,1,1) do @for /f "tokens=1,2* delims=:" %a in (\'findstr /n /r "^" README ^| findstr /r "^%l:"\') do @echo %b') @@ -572,6 +585,7 @@ def BuildRelease(target, source, env): os.system('for /l %l in (1,1,2) do @for /f "tokens=1,2* delims=:" %a in (\'findstr /n /r "^" LICENSE ^| findstr /r "^%l:"\') do @echo %b') else: os.system('head -n 2 LICENSE') + #if (raw_input("Go ahead and build installer (yes/[no])? ") == "yes"): if True: # TODO(XXX): Installing a runtime isn't specific to MSVS? @@ -715,7 +729,7 @@ def BuildRelease(target, source, env): command = '"%(wix)s\\light.exe" -cc .\ -nologo -sw1076 -spdb -ext WixUIExtension -cultures:%(deflang)s -loc build\wix\Localization\mixxx_%(deflang)s.wxl -out %(package_name)s build\wix\*.wixobj build\wix\subdirs\*.wixobj' % \ {'wix': wix_path, 'deflang': defaultLanguage, - 'package_name': 'part.' + exe_name} + 'package_name': 'part.' + msi_name} print("Using Command: " + command) subprocess.check_call(command) @@ -764,14 +778,14 @@ def BuildRelease(target, source, env): command = '"%(wix)s\\torch.exe" -nologo -p -t language %(package_name)s %(lang)s.msi -o %(lang)s.mst' % \ {'wix': wix_path, 'lang': culture, - 'package_name': 'part.' + exe_name} + 'package_name': 'part.' + msi_name} print("Using Command: " + command) subprocess.check_call(command) command = 'cscript "%(winsdk)s\wisubstg.vbs" %(package_name)s %(lang)s.mst %(langid)s' % \ {'winsdk': WinSDK_path, 'lang': culture, - 'package_name': 'part.' + exe_name, + 'package_name': 'part.' + msi_name, 'langid': LCID} print("Using Command: " + command) subprocess.check_call(command) @@ -783,7 +797,7 @@ def BuildRelease(target, source, env): print("*** Add all supported languages to MSI Package attribute") command = 'cscript "%(winsdk)s\WiLangId.vbs" %(package_name)s Package %(langid)s' % \ {'winsdk': WinSDK_path, - 'package_name': 'part.' + exe_name, + 'package_name': 'part.' + msi_name, 'langid': langIds} print("Using Command: " + command) subprocess.check_call(command) @@ -794,9 +808,9 @@ def BuildRelease(target, source, env): bundlelocfile.close() # Everything is OK, now rename the msi to final name - if os.path.isfile(exe_name): - os.remove(exe_name) - os.rename('part.' + exe_name, exe_name) + if os.path.isfile(msi_name): + os.remove(msi_name) + os.rename('part.' + msi_name, msi_name) print("*** Compiling Bundle") # Compile bundle wix file @@ -804,7 +818,7 @@ def BuildRelease(target, source, env): {'wix': wix_path, 'winlibpath': build.winlib_path, 'arch': winArch, - 'package_name': exe_name} + 'package_name': msi_name} print("Using Command: " + command) subprocess.check_call(command) # bundle localisation references @@ -812,17 +826,48 @@ def BuildRelease(target, source, env): {'wix': wix_path, 'winlibpath': build.winlib_path, 'arch': winArch, - 'package_name': exe_name} + 'package_name': msi_name} print("Using Command: " + command) subprocess.check_call(command) + exe_name = os.path.splitext(msi_name)[0] + '.exe' command = '"%(wix)s\\light.exe" -cc .\ -nologo -sw1076 -spdb -ext WixUtilExtension -ext WixBalExtension -dMSIPackage=%(msi_name)s -cultures:%(deflang)s -loc build\wix\Localization\mixxx_%(deflang)s.wxl -out %(package_name)s build\\wix\\bundle\\*.wixobj' % \ {'wix': wix_path, 'deflang': defaultLanguage, - 'msi_name': exe_name, - 'package_name': os.path.splitext(exe_name)[0] + '.exe'} + 'msi_name': msi_name, + 'package_name': exe_name} print("Using Command: " + command) subprocess.check_call(command) + if 'sign' in COMMAND_LINE_TARGETS: + from build.windows import signtool + codesign_subject_name = SCons.ARGUMENTS.get('windows_codesign_subject_name', '') + if not codesign_subject_name: + raise Exception('Code-signing was requested but windows_codesign_subject_name was not provided.') + + print("*** Signing Bundle") + # In addition to simply signing the installer executable, we have to + # extract and sign the "burn engine". See + # http://wixtoolset.org/documentation/manual/v3/overview/insignia.html for details. + command = ("%(wix)s\\insignia.exe -ib %(package_name)s -o setup.exe" % { + "wix": wix_path, + "package_name": exe_name, + }) + print("Using Command: " + command) + subprocess.check_call(command) + + # Imperatively sign the file since the whole WiX process is imperative. + signtool.signtool_path(codesign_subject_name, 'setup.exe') + + command = ("%(wix)s\\insignia.exe -ab setup.exe %(package_name)s -o %(package_name)s" % { + "wix": wix_path, + "package_name": exe_name, + }) + print("Using Command: " + command) + subprocess.check_call(command) + + # Now sign the final package imperatively. + signtool.signtool_path(codesign_subject_name, exe_name) + # Some cleaning before leaving for file in glob.glob('*.cab'): os.remove(file) @@ -832,7 +877,7 @@ def BuildRelease(target, source, env): os.remove(file) for file in glob.glob('build\wix\subdirs\*.wxs'): os.remove(file) - os.remove(exe_name) + os.remove(msi_name) else: print("Aborted building installer") @@ -1109,5 +1154,5 @@ versiondebbld = Builder(action = BuildUbuntuPackage) #, suffix = '.foo', src_suf env.Append(BUILDERS = {'BuildUbuntuPackage' : versiondebbld}) if 'makeubuntu' in COMMAND_LINE_TARGETS: - makeubuntu = env.BuildUbuntuPackage("blah", "defs_version.h" ) #(binary_files) + makeubuntu = env.BuildUbuntuPackage("blah", "src/defs_version.h" ) #(binary_files) env.Alias('makeubuntu', makeubuntu) diff --git a/src/SConscript.env b/SConscript.env index 17ea54e5c8..2ced2f7245 100644 --- a/src/SConscript.env +++ b/SConscript.env @@ -9,26 +9,29 @@ import shutil from build import util, mixxx, depends +print('SConscript.env cwd: ' + os.getcwd()) Import('build') # Grab the created environment from the MixxxBuild env = build.env -# Check for old build.h file and delete it if it exists -defs = str(SCons.Script.File('#src/build.h')) -if os.path.exists(defs): - print("Deleting deprecated build file: %s" % defs) - os.remove(defs) +# We are in the variant_dir (win|mac|lin)XX_build, and the 'src' subdirectory +# may not exist yet. +try: + os.mkdir('src') +except: + pass -if os.path.exists(os.path.join('..', 'build.h')): +# TODO(rryan): This logic should be written in a more SCons-friendly way, since +# it depends on the cwd being the variant_dir to work properly. +if os.path.exists('../build.h'): # If a build.h exists in the project root mixxx/ directory then use that # instead of writing our own. This is mostly since when we build Debian - # packages we don't have any of the Bazaar metadata so we can't write one + # packages we don't have any of the Git metadata so we can't write one # ourselves. - shutil.copy(os.path.join('..', 'build.h'), 'build.h') + shutil.copy('../build.h', 'src/build.h') else: - util.write_build_header('build.h') - + util.write_build_header('src/build.h') conf = Configure(env, custom_tests = { 'CheckForPKGConfig' : util.CheckForPKGConfig, 'CheckForPKG' : util.CheckForPKG }) @@ -128,7 +131,7 @@ build_flags = ' '.join(sorted( [('%s=%s' % (k,v) if v is not None else k) for k,v in build.flags.items() if v is not None])) ### Put flags info into a file -with open("build.h","a") as f: +with open("src/build.h", "a") as f: f.write('#define BUILD_FLAGS "' + build_flags + '"\n') # Print the build flags. This is useful if the flags have been cached, diff --git a/SConstruct b/SConstruct index 7b4e22857e..910ac5d956 100644 --- a/SConstruct +++ b/SConstruct @@ -60,7 +60,6 @@ available_features = [features.Mad, # "Features" of dubious quality features.PerfTools, features.AsmLib, - features.IPod, features.FFMPEG, # Experimental features @@ -74,14 +73,35 @@ Export('build') # Run our configuration stuff to setup our build environment (detect # platform/arch, find libraries, etc) -SConscript(File('src/SConscript.env'), variant_dir=Dir(build.build_dir), duplicate=0) + +# If the variant_dir does not exist then we will not chdir into it when calling +# SConscript.env, making the imperative logic (e.g. writing build.h) in +# SConscript.env behave differently on the first invocation vs. subsequent +# invocations. +try: + os.mkdir(build.build_dir) +except: + pass +SConscript('SConscript.env', variant_dir=build.build_dir, duplicate=0) # Grab the list of sources generated by SConscript.env Import('sources') +# Produce compile_commands.json, which is used by clang-tidy and related tools. +build.env.Tool("compile_commands") +build.env.Alias("compiledb", build.env.CompilationDatabase('compile_commands.json')) +# Build compile_commands.json by default. +build.env.Default("compile_commands.json") + +# Build VAMP plugins. +mixxxminimal_plugins = SConscript( + 'vamp-plugins/SConscript', + variant_dir=build.build_dir + "/vamp-plugins", + duplicate=0, exports=['build']) + # Setup and build the "mixxx" executable target. Also sets up our install # targets for each platform. -SConscript(File('src/SConscript'), variant_dir=Dir(build.build_dir), duplicate=0, +SConscript('SConscript', variant_dir=build.build_dir, duplicate=0, exports=['build', 'sources']) #On OS X, if the bundle has been built, copy it up: diff --git a/build/compile_commands.py b/build/compile_commands.py new file mode 100644 index 0000000000..161ac6061e --- /dev/null +++ b/build/compile_commands.py @@ -0,0 +1,197 @@ +# Copyright 2015 MongoDB Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import SCons +import itertools + +# Implements the ability for SCons to emit a compilation database for the MongoDB project. See +# http://clang.llvm.org/docs/JSONCompilationDatabase.html for details on what a compilation +# database is, and why you might want one. The only user visible entry point here is +# 'env.CompilationDatabase'. This method takes an optional 'target' to name the file that +# should hold the compilation database, otherwise, the file defaults to compile_commands.json, +# which is the name that most clang tools search for by default. + +# TODO: Is there a better way to do this than this global? Right now this exists so that the +# emitter we add can record all of the things it emits, so that the scanner for the top level +# compilation database can access the complete list, and also so that the writer has easy +# access to write all of the files. But it seems clunky. How can the emitter and the scanner +# communicate more gracefully? +__COMPILATION_DB_ENTRIES=[] + +# Cribbed from Tool/cc.py and Tool/c++.py. It would be better if +# we could obtain this from SCons. +_CSuffixes = ['.c'] +if not SCons.Util.case_sensitive_suffixes('.c', '.C'): + _CSuffixes.append('.C') + +_CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++'] +if SCons.Util.case_sensitive_suffixes('.c', '.C'): + _CXXSuffixes.append('.C') + +# We make no effort to avoid rebuilding the entries. Someday, perhaps we could and even +# integrate with the cache, but there doesn't seem to be much call for it. +class __CompilationDbNode(SCons.Node.Python.Value): + def __init__(self, value): + SCons.Node.Python.Value.__init__(self, value) + self.Decider(changed_since_last_build_node) + + +def changed_since_last_build_node(node, target, prev_ni): + """ Dummy decider to force alwasy building""" + return True + + +def makeEmitCompilationDbEntry(comstr): + """ |