From c2fa8b4b4dd377afaf300ff4d74835eb370cfcf5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 30 Jun 2015 14:04:45 -0700 Subject: [PATCH] skeleton --- .gitignore | 1 + .ycm_extra_conf.py | 126 ++++++++++++++++++++++++++++ CMakeLists.txt | 165 +++++++++++++++++++++++++++++++++++++ cmake/FindPulseAudio.cmake | 16 ++++ example/noise.c | 0 src/config.h.in | 11 +++ src/soundio.c | 0 src/soundio.h | 0 test/unit_tests.c | 0 9 files changed, 319 insertions(+) create mode 100644 .gitignore create mode 100644 .ycm_extra_conf.py create mode 100644 CMakeLists.txt create mode 100644 cmake/FindPulseAudio.cmake create mode 100644 example/noise.c create mode 100644 src/config.h.in create mode 100644 src/soundio.c create mode 100644 src/soundio.h create mode 100644 test/unit_tests.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 0000000..701016f --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,126 @@ +import os +import ycm_core +import subprocess + +def DirectoryOfThisScript(): + return os.path.dirname( os.path.abspath( __file__ ) ) + +def ExtractSearchPaths(compiler): + def find_paths(compiler, c_arg): + child = subprocess.Popen([compiler, c_arg, '-E', '-v', '-'], stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + stderr, stdout = child.communicate(input="") + lines = stdout.split("\n") + begin_token = '#include <...> search starts here:' + end_token = 'End of search list.' + + def find_token_index(l, token): + for index, item in enumerate(l): + if item == token: + return index + raise Exception("token not found: %s" % token) + begin_index = find_token_index(lines, begin_token) + end_index = find_token_index(lines, end_token) + return map(lambda x: x.strip(), lines[begin_index+1:end_index]) + + results = find_paths(compiler, '-xc') + results.extend(find_paths(compiler, '-xc++')) + return results + +# 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 = os.path.join(DirectoryOfThisScript(), 'build') +compiler = os.environ['CC'] +search_paths = ExtractSearchPaths(compiler) +extra_flags = [] +for path in search_paths: + extra_flags.append('-I') + extra_flags.append(path) + +if os.path.exists( compilation_database_folder ): + database = ycm_core.CompilationDatabase( compilation_database_folder ) +else: + raise Exception("compilation database not found") + +SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] + + +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 ): + # 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_ ) + + relative_to = DirectoryOfThisScript() + moar_flags = MakeRelativePathsInFlagsAbsolute( extra_flags, relative_to ) + + final_flags.extend(moar_flags) + + return { + 'flags': final_flags, + 'do_cache': True + } diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2e28225 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,165 @@ +cmake_minimum_required(VERSION 2.8) +cmake_policy(SET CMP0042 NEW) +cmake_policy(SET CMP0046 NEW) +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug" CACHE STRING + "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) +endif() + +project(libsoundio C) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) + +set(LIBSOUNDIO_VERSION_MAJOR 0) +set(LIBSOUNDIO_VERSION_MINOR 0) +set(LIBSOUNDIO_VERSION_PATCH 0) +set(LIBSOUNDIO_VERSION "${LIBSOUNDIO_VERSION_MAJOR}.${LIBSOUNDIO_VERSION_MINOR}.${LIBSOUNDIO_VERSION_PATCH}") +message("Configuring libsoundio version ${LIBSOUNDIO_VERSION}") + +set(LIBSOUNDIO_SOURCES + "${CMAKE_SOURCE_DIR}/src/soundio.c" +) +set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h") +set(LIBSOUNDIO_HEADERS + "${CMAKE_SOURCE_DIR}/src/soundio.h" + ${CONFIGURE_OUT_FILE} +) + +set(TEST_SOURCES + "${CMAKE_SOURCE_DIR}/test/unit_tests.c" +) + +find_package(Threads) +if(Threads_FOUND) + set(STATUS_THREADS "OK") +else(Threads_FOUND) + set(STATUS_THREADS "not found") +endif(Threads_FOUND) + + +find_package(PulseAudio) +if(PULSEAUDIO_FOUND) + set(STATUS_PULSEAUDIO "OK") +else() + set(STATUS_PULSEAUDIO "not found") +endif() + +if(APPLE) + set(SOUNDIO_HAVE_ALSA false) + set(STATUS_ALSA "OK") +else() + set(SOUNDIO_HAVE_ALSA true) + find_package(ALSA) + if(ALSA_FOUND) + set(STATUS_ALSA "OK") + else() + set(STATUS_ALSA "not found") + endif() +endif() + +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-unused-variable") + + +set(LIB_CFLAGS "-std=c11 -Werror -Wall -fdiagnostics-color=auto") +set(EXAMPLE_CFLAGS "-std=c99 -pedantic -Werror -Wall") +set(EXAMPLE_INCLUDES "${CMAKE_SOURCE_DIR}/src") +set(TEST_CFLAGS "${LIB_CFLAGS} -fprofile-arcs -ftest-coverage") +set(TEST_LDFLAGS "-fprofile-arcs -ftest-coverage") +set(TEST_INCLUDES "${CMAKE_SOURCE_DIR}/test") + +configure_file ( + "${CMAKE_SOURCE_DIR}/src/config.h.in" + ${CONFIGURE_OUT_FILE} +) + +add_library(libsoundio_shared SHARED ${LIBSOUNDIO_SOURCES}) +set_target_properties(libsoundio_shared PROPERTIES + OUTPUT_NAME soundio + SOVERSION ${LIBSOUNDIO_VERSION_MAJOR} + VERSION ${LIBSOUNDIO_VERSION} + COMPILE_FLAGS ${LIB_CFLAGS} + LINKER_LANGUAGE C +) +include_directories( + ${CMAKE_SOURCE_DIR} + ${PULSEAUDIO_INCLUDE_DIR} + ${CMAKE_BINARY_DIR} + ${ALSA_INCLUDE_DIRS} +) +target_link_libraries(libsoundio_shared LINK_PUBLIC + ${PULSEAUDIO_LIBRARY} + ${ALSA_LIBRARIES} + m + ${CMAKE_THREAD_LIBS_INIT} +) +install(TARGETS libsoundio_shared DESTINATION lib) + + +add_library(libsoundio_static STATIC ${LIBSOUNDIO_SOURCES}) +set_target_properties(libsoundio_static PROPERTIES + OUTPUT_NAME soundio + COMPILE_FLAGS ${LIB_CFLAGS} + LINKER_LANGUAGE C +) +install(TARGETS libsoundio_static DESTINATION lib) + +install(FILES + ${LIBSOUNDIO_HEADERS} + ${CONFIGURE_OUT_FILE} + DESTINATION "include/soundio") + +# Example Programs + +add_executable(noise example/noise.c) +set_target_properties(noise PROPERTIES + LINKER_LANGUAGE C + COMPILE_FLAGS ${EXAMPLE_CFLAGS}) +include_directories(${EXAMPLE_INCLUDES}) +target_link_libraries(noise libsoundio_shared) + + + +enable_testing() +add_executable(unit_tests ${TEST_SOURCES}) +target_link_libraries(unit_tests LINK_PUBLIC + ${CMAKE_THREAD_LIBS_INIT} + ${PULSEAUDIO_LIBRARY} + ${ALSA_LIBRARIES} + m +) +set_target_properties(unit_tests PROPERTIES + LINKER_LANGUAGE C + COMPILE_FLAGS ${TEST_CFLAGS} + LINK_FLAGS ${TEST_LDFLAGS} +) +include_directories(${TEST_INCLUDES}) +add_test(UnitTests unit_tests) + + +add_custom_target(coverage + DEPENDS unit_tests + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1 + COMMAND ./unit_tests + COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1 + COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1 + COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1 + COMMAND rm coverage.info coverage.info.cleaned +) + + + +message("\n" + "Installation Summary\n" + "--------------------\n" + "* Install Directory : ${CMAKE_INSTALL_PREFIX}\n" +) + +message( + "System Dependencies\n" + "-------------------\n" + "* threads : ${STATUS_THREADS}\n" + "* pulseaudio : ${STATUS_PULSEAUDIO}\n" + "* ALSA : ${STATUS_ALSA}\n" +) diff --git a/cmake/FindPulseAudio.cmake b/cmake/FindPulseAudio.cmake new file mode 100644 index 0000000..14bcadd --- /dev/null +++ b/cmake/FindPulseAudio.cmake @@ -0,0 +1,16 @@ +# Copyright (c) 2015 Andrew Kelley +# This file is MIT licensed. +# See http://opensource.org/licenses/MIT + +# PULSEAUDIO_FOUND +# PULSEAUDIO_INCLUDE_DIR +# PULSEAUDIO_LIBRARY + +find_path(PULSEAUDIO_INCLUDE_DIR NAMES pulse/pulseaudio.h) + +find_library(PULSEAUDIO_LIBRARY NAMES pulse) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PULSEAUDIO DEFAULT_MSG PULSEAUDIO_LIBRARY PULSEAUDIO_INCLUDE_DIR) + +mark_as_advanced(PULSEAUDIO_INCLUDE_DIR PULSEAUDIO_LIBRARY) diff --git a/example/noise.c b/example/noise.c new file mode 100644 index 0000000..e69de29 diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 0000000..cb37e96 --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,11 @@ +#ifndef SOUNDIO_CONFIG_H +#define SOUNDIO_CONFIG_H + +#define SOUNDIO_VERSION_MAJOR @LIBSOUNDIO_VERSION_MAJOR@ +#define SOUNDIO_VERSION_MINOR @LIBSOUNDIO_VERSION_MINOR@ +#define SOUNDIO_VERSION_PATCH @LIBSOUNDIO_VERSION_PATCH@ +#define SOUNDIO_VERSION_STRING "@LIBSOUNDIO_VERSION@" + +#cmakedefine SOUNDIO_HAVE_ALSA + +#endif diff --git a/src/soundio.c b/src/soundio.c new file mode 100644 index 0000000..e69de29 diff --git a/src/soundio.h b/src/soundio.h new file mode 100644 index 0000000..e69de29 diff --git a/test/unit_tests.c b/test/unit_tests.c new file mode 100644 index 0000000..e69de29