Skip to content

Commit

Permalink
refactor on build system
Browse files Browse the repository at this point in the history
  • Loading branch information
flplv committed Feb 10, 2017
1 parent 2bfab5f commit adca040
Show file tree
Hide file tree
Showing 22 changed files with 265 additions and 20 deletions.
193 changes: 193 additions & 0 deletions .ycm_extra_conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# This file is NOT licensed under the GPLv3, which is the license for the rest
# of YouCompleteMe.
#
# Here's the license text for this file:
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>

# These are the compilation flags that will be used in case there's no
# compilation database set (by default, one is not set).
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
module_name = "ycm_flags"
modyle_path = ".ycm_flags.py.host_tests"
# try:
import sys
if sys.version_info[0] < 3:
from imp import load_source
ycm_flags = load_source(module_name, modyle_path)
flags = ycm_flags.flags
else:
if sys.version_info[1] < 5:
import importlib.util
spec = importlib.util.spec_from_file_location(module_name, modyle_path)
ycm_flags = importlib.util.module_from_spec(spec)
spec.loader.exec_module(ycm_flags)
flags = ycm_flags.flags
else:
from importlib.machinery import SourceFileLoader
ycm_flags = SourceFileLoader(modyle_name, modyle_path).load_module()
flags = ycm_flags.flags

# except:
# flags = [
# '-Wall',
# #'-Wextra',
# '-Werror',
# #'-Wc++98-compat',
# '-Wno-long-long',
# '-Wno-variadic-macros',
# '-fexceptions',
# # THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
# # language to use when compiling headers. So it will guess. Badly. So C++
# # headers will be compiled as C headers. You don't want that so ALWAYS specify
# # a "-std=<something>".
# # For a C project, you would set this to something like 'c99' instead of
# # 'c++11'.
# '-std=c++11',
# # ...and the same thing goes for the magic -x option which specifies the
# # language that the files to be compiled are written in. This is mostly
# # relevant for c++ headers.
# # For a C project, you would set this to 'c' instead of 'c++'.
# '-x',
# 'c++',
# # You can add the specified directory to the search path for
# # system include files.
# #'-isystem',
# #'/usr/include/c++/5',
# # You can add the specified directory to the search path for
# # include files.
# #'-I',
# #'/usr/include/gmock',
# ]

print flags

import os
import ycm_core


# Set this to the absolute path to the folder (NOT the file!) containing the
# compile_commands.json file to use that instead of 'flags'. See here for
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
#
# You can get CMake to generate this file for you by adding:
# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
# to your CMakeLists.txt file.
#
# Most projects will NOT need to set this to anything; you can just change the
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
compilation_database_folder = ''

if os.path.exists( compilation_database_folder ):
database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
database = None

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]

def DirectoryOfThisScript():
return os.path.dirname( os.path.abspath( __file__ ) )


def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
if not working_directory:
return list( flags )
new_flags = []
make_next_absolute = False
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
for flag in flags:
new_flag = flag

if make_next_absolute:
make_next_absolute = False
if not flag.startswith( '/' ):
new_flag = os.path.join( working_directory, flag )

for path_flag in path_flags:
if flag == path_flag:
make_next_absolute = True
break

if flag.startswith( path_flag ):
path = flag[ len( path_flag ): ]
new_flag = path_flag + os.path.join( working_directory, path )
break

if new_flag:
new_flags.append( new_flag )
return new_flags


def IsHeaderFile( filename ):
extension = os.path.splitext( filename )[ 1 ]
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]


def GetCompilationInfoForFile( filename ):
# The compilation_commands.json file generated by CMake does not have entries
# for header files. So we do our best by asking the db for flags for a
# corresponding source file, if any. If one exists, the flags for that file
# should be good enough.
if IsHeaderFile( filename ):
basename = os.path.splitext( filename )[ 0 ]
for extension in SOURCE_EXTENSIONS:
replacement_file = basename + extension
if os.path.exists( replacement_file ):
compilation_info = database.GetCompilationInfoForFile(
replacement_file )
if compilation_info.compiler_flags_:
return compilation_info
return None
return database.GetCompilationInfoForFile( filename )


def FlagsForFile( filename, **kwargs ):
if database:
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
# python list, but a "list-like" StringVec object
compilation_info = GetCompilationInfoForFile( filename )
if not compilation_info:
return None

final_flags = MakeRelativePathsInFlagsAbsolute(
compilation_info.compiler_flags_,
compilation_info.compiler_working_dir_ )

# NOTE: This is just for YouCompleteMe; it's highly likely that your project
# does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
# ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.
try:
final_flags.remove( '-stdlib=libc++' )
except ValueError:
pass
else:
relative_to = DirectoryOfThisScript()
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )

return {
'flags': final_flags,
'do_cache': True
}
9 changes: 9 additions & 0 deletions Sconstruct
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ def ObjectsToGcov(self, source_list):
return r
default_env.AddMethod(ObjectsToGcov)

# Create -include flags
def UpdateIncludes(self):
env = {
'CXXFLAGS': sum([['-include', i] for i in self['CXXINCLUDES']], []),
'CFLAGS' : sum([['-include', i] for i in self['CINCLUDES']], [])
}
self.Prepend(**env)
default_env.AddMethod(UpdateIncludes)

def EnablePlatformsFor(build_name, available_platforms):
r = []
for plat in available_platforms:
Expand Down
25 changes: 25 additions & 0 deletions build_platforms/PlatformBaseClass.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,31 @@ def BuildListAddDirectory (self, build_name, path):
def PostBuildTargets(self):
pass

@staticmethod
def MakeYCMFlags(target, source, env):
from SCons.Node.FS import File, Dir
from SCons.Node import NodeList
def flatten(xs):
result = []
if isinstance(xs, (list, tuple, NodeList)):
for x in xs:
result.extend(flatten(x))
else:
result.append(xs)
return result
def toPath(f):
if isinstance(f, (File, Dir)):
return str(f.path)
return f
flags = flatten(env['CXXFLAGS']) + flatten(env['CFLAGS']) \
+ ['-D ' + define for define in flatten(env['CPPDEFINES'])] \
+ ['-I ' + toPath(inc) for inc in flatten(env['CPPPATH'])] \
+ ['-l ' + toPath(lib) for lib in flatten(env['LIBS'])] \
+ ['-include ' + toPath(inc) for inc in flatten(env['CINCLUDES'])] \
+ ['-include ' + toPath(inc) for inc in flatten(env['CXXINCLUDES'])]
with open(target[0].path, "w") as flags_file:
flags_file.write("flags={}".format(flags))

class Default(object):
def __init__(self, target):
self._target = target
Expand Down
3 changes: 2 additions & 1 deletion build_platforms/host.sconscript
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class HostPlatform(PlatformBaseClass):
'-Wall', '-Wextra', '-Wswitch-default', '-Wswitch-enum', '-Wconversion', '-Wno-long-long'],
CPPDEFINES = ['REACTO_ENABLE_DEBUG'],
LIBS = ['pthread'],
CPPINCLUDES = []
CINCLUDES = [],
CXXINCLUDES = [],
)

instance = HostPlatform()
Expand Down
11 changes: 8 additions & 3 deletions build_platforms/host_tests.sconscript
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ class HostTestsPlatform(PlatformBaseClass):
return [self.Default('tests'),
'coverage', self.Default('coverage_report'),
str(self._build_libraries['reacto']),
str(self._build_binaries['reacto_tests'])]
str(self._build_binaries['reacto_tests']),
'.ycm_flags.py.{}'.format(self.Name())]

def BuildList(self):
return [
'cpputest',
'reacto',
'reacto_tests'
'reacto_tests',
]

def ProfileEnabled(self):
Expand All @@ -26,6 +27,9 @@ class HostTestsPlatform(PlatformBaseClass):
return True

def PostBuildTargets(self):
self.Env().Command( target = '.ycm_flags.py.{}'.format(self.Name()),
source = "",
action = PlatformBaseClass.MakeYCMFlags)
#
#
# Tests Build
Expand Down Expand Up @@ -94,7 +98,8 @@ class HostTestsPlatform(PlatformBaseClass):
'-Wall', '-Wextra', '-Wswitch-default', '-Wswitch-enum', '-Wconversion', '-Wno-long-long'],
CPPDEFINES = ['REACTO_ENABLE_DEBUG'],
LIBS = ['pthread'],
CPPINCLUDES = []
CINCLUDES = [],
CXXINCLUDES = [],
)

instance = HostTestsPlatform()
Expand Down
3 changes: 2 additions & 1 deletion build_platforms/mcp430.sconscript
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ class Msp430Platform(PlatformBaseClass):
CPPFLAGS = ['-g', '-Os', '-Wall'],
LINKFLAGS = [mcu_flag,
],
CPPINCLUDES = [],
CINCLUDES = [],
CXXINCLUDES = [],
)

instance = Msp430Platform()
Expand Down
16 changes: 9 additions & 7 deletions dependencies/cpputest/Sconscript
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ cpputest_exports = {
# Scons has no support for gcc -include command line option,
# we have to do some workaround.
'CXXFLAGS' : [
'-include',
new_macros,
'-include',
malloc_macros
# '-include',
# new_macros,
# '-include',
# malloc_macros
],
'CFLAGS' : [
'-include',
malloc_macros
# '-include',
# malloc_macros
],
'CPPPATH' : [ cpputest_include, Dir('./include') ],
# This is a ugly workaround becouse scons doesn't detect dependency on C*FLAGS
# every single build will have to add CPPINCLUDES dependency to their's .o
'CPPINCLUDES' : [new_macros, malloc_macros]
'CXXINCLUDES' : [new_macros],
'CINCLUDES' : [malloc_macros],
}

# Download and extract cpputest-3.8.tar.gz to cpputest-tree
Expand All @@ -36,6 +37,7 @@ for plat in platforms:
# Modify imported environment to be used by further builds
plat.Env().Prepend(**cpputest_exports)
env = plat.Env().Clone()
env.UpdateIncludes()

# Call script to build cpputest
config = {'cpputest_extensions_enabled' : plat.CppUTestExtensionsEnabled()}
Expand Down
2 changes: 1 addition & 1 deletion dependencies/cpputest/Sconscript.variant
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ src = env.MultiLineStringToFiles(src_str)
objs = env.SourceToObjects(src)
src_ext = env.MultiLineStringToFiles(src_ext_str)
objs_ext = env.SourceToObjects(src_ext)
Depends(src + objs + src_ext + objs_ext, env['CPPINCLUDES'])
#Depends(src + objs + src_ext + objs_ext, env['CXXINCLUDES'] + env['CINCLUDES'])

r = { 'libs' : [], 'path' : [] }
lib_cpputest = env.StaticLibrary('cpputest', src)
Expand Down
1 change: 1 addition & 0 deletions examples/msp430_blink/Sconscript
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Import('platforms')
for plat in platforms:
name = plat.Name()
env = plat.Env().Clone()
env.UpdateIncludes()
build_dir = './build/' + name
exe = env.SConscript('./Sconscript.variant', exports = ['name','env'], variant_dir = build_dir, src = 'tests', duplicate=0)

Expand Down
2 changes: 1 addition & 1 deletion examples/msp430_blink/Sconscript.variant
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ env.Append(LINKFLAGS = ['-Xlinker', '-Map=' + map_file])

sources = [File('main.c')]
objects = env.SourceToObjects(sources)
Depends(objects, env['CPPINCLUDES'])
Depends(objects, env['CXXINCLUDES'] + env['CINCLUDES'])

exes = env.Program(['../msp430_blink_' + name + '.elf', map_file], sources)
exe = {'exe': exes[0], 'map': exes[1]}
Expand Down
1 change: 1 addition & 0 deletions examples/msp430_realtime_blink/Sconscript
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Import('platforms')
for plat in platforms:
name = plat.Name()
env = plat.Env().Clone()
env.UpdateIncludes()
build_dir = './build/' + name
exe = env.SConscript('./Sconscript.variant', exports = ['name','env'], variant_dir = build_dir, src = 'tests', duplicate=0)

Expand Down
2 changes: 1 addition & 1 deletion examples/msp430_realtime_blink/Sconscript.variant
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ env.Append(LINKFLAGS = ['-Xlinker', '-Map=' + map_file])

sources = [File('main.c')]
objects = env.SourceToObjects(sources)
Depends(objects, env['CPPINCLUDES'])
Depends(objects, env['CXXINCLUDES'] + env['CINCLUDES'])

exes = env.Program(['../msp430_realtime_blink_' + name + '.elf', map_file], sources)
exe = {'exe': exes[0], 'map': exes[1]}
Expand Down
1 change: 1 addition & 0 deletions examples/msp430_timed_blink/Sconscript
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Import('platforms')
for plat in platforms:
name = plat.Name()
env = plat.Env().Clone()
env.UpdateIncludes()
build_dir = './build/' + name
exe = env.SConscript('./Sconscript.variant', exports = ['name','env'], variant_dir = build_dir, src = 'tests', duplicate=0)

Expand Down
2 changes: 1 addition & 1 deletion examples/msp430_timed_blink/Sconscript.variant
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ env.Append(LINKFLAGS = ['-Xlinker', '-Map=' + map_file])

sources = [File('main.c')]
objects = env.SourceToObjects(sources)
Depends(objects, env['CPPINCLUDES'])
Depends(objects, env['CXXINCLUDES'] + env['CINCLUDES'])

exes = env.Program(['../msp430_timed_blink_' + name + '.elf', map_file], sources)
exe = {'exe': exes[0], 'map': exes[1]}
Expand Down
Loading

0 comments on commit adca040

Please sign in to comment.