Fix build system
This commit is contained in:
parent
4b4ce45804
commit
e5e972fc4a
|
@ -1 +1 @@
|
||||||
NESEmulator
|
nes_emulator
|
|
@ -1,5 +1,11 @@
|
||||||
|
set(CMAKE_C_COMPILER gcc)
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(NESEmulator VERSION 0.1)
|
project(nes_emulator LANGUAGES C VERSION 0.1 )
|
||||||
|
|
||||||
|
add_subdirectory(libs/log.c)
|
||||||
|
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/libs/log.c/src ${COMMON_INCLUDES})
|
||||||
|
|
||||||
add_subdirectory(cpu)
|
add_subdirectory(cpu)
|
||||||
add_subdirectory(ppu)
|
add_subdirectory(ppu)
|
||||||
|
@ -16,14 +22,12 @@ list(APPEND EXTRA_INCLUDES
|
||||||
"${PROJECT_SOURCE_DIR}/debugger"
|
"${PROJECT_SOURCE_DIR}/debugger"
|
||||||
"${PROJECT_SOURCE_DIR}/utils")
|
"${PROJECT_SOURCE_DIR}/utils")
|
||||||
|
|
||||||
add_executable(NESEmulator main.c
|
set(HEADERS include/system.h include/types.h)
|
||||||
system.c
|
set(SOURCE main.c system.c)
|
||||||
include/system.h
|
|
||||||
include/types.h)
|
|
||||||
|
|
||||||
find_package(log.c)
|
add_executable(nes_emulator ${HEADERS} ${SOURCE})
|
||||||
|
|
||||||
target_link_libraries(NESEmulator CPU PPU Mappers ROM DEBUG UTILS log.c::log.c)
|
target_link_libraries(nes_emulator nes_cpu nes_ppu nes_mappers nes_rom nes_debugger nes_utils log.c)
|
||||||
target_include_directories(NESEmulator PUBLIC
|
target_include_directories(nes_emulator PUBLIC
|
||||||
"${PROJECT_BINARY_DIR}"
|
"${PROJECT_BINARY_DIR}"
|
||||||
${EXTRA_INCLUDES})
|
${EXTRA_INCLUDES})
|
|
@ -1,548 +0,0 @@
|
||||||
# This file is managed by Conan, contents will be overwritten.
|
|
||||||
# To keep your changes, remove these comment lines, but the plugin won't be able to modify your requirements
|
|
||||||
|
|
||||||
set(CONAN_MINIMUM_VERSION 2.0.5)
|
|
||||||
|
|
||||||
|
|
||||||
function(detect_os OS OS_API_LEVEL OS_SDK OS_SUBSYSTEM OS_VERSION)
|
|
||||||
# it could be cross compilation
|
|
||||||
message(STATUS "CMake-Conan: cmake_system_name=${CMAKE_SYSTEM_NAME}")
|
|
||||||
if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic")
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
|
||||||
set(${OS} Macos PARENT_SCOPE)
|
|
||||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "QNX")
|
|
||||||
set(${OS} Neutrino PARENT_SCOPE)
|
|
||||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN")
|
|
||||||
set(${OS} Windows PARENT_SCOPE)
|
|
||||||
set(${OS_SUBSYSTEM} cygwin PARENT_SCOPE)
|
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "^MSYS")
|
|
||||||
set(${OS} Windows PARENT_SCOPE)
|
|
||||||
set(${OS_SUBSYSTEM} msys2 PARENT_SCOPE)
|
|
||||||
else()
|
|
||||||
set(${OS} ${CMAKE_SYSTEM_NAME} PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
|
|
||||||
string(REGEX MATCH "[0-9]+" _OS_API_LEVEL ${ANDROID_PLATFORM})
|
|
||||||
message(STATUS "CMake-Conan: android_platform=${ANDROID_PLATFORM}")
|
|
||||||
set(${OS_API_LEVEL} ${_OS_API_LEVEL} PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS")
|
|
||||||
# CMAKE_OSX_SYSROOT contains the full path to the SDK for MakeFile/Ninja
|
|
||||||
# generators, but just has the original input string for Xcode.
|
|
||||||
if(NOT IS_DIRECTORY ${CMAKE_OSX_SYSROOT})
|
|
||||||
set(_OS_SDK ${CMAKE_OSX_SYSROOT})
|
|
||||||
else()
|
|
||||||
if(CMAKE_OSX_SYSROOT MATCHES Simulator)
|
|
||||||
set(apple_platform_suffix simulator)
|
|
||||||
else()
|
|
||||||
set(apple_platform_suffix os)
|
|
||||||
endif()
|
|
||||||
if(CMAKE_OSX_SYSROOT MATCHES AppleTV)
|
|
||||||
set(_OS_SDK "appletv${apple_platform_suffix}")
|
|
||||||
elseif(CMAKE_OSX_SYSROOT MATCHES iPhone)
|
|
||||||
set(_OS_SDK "iphone${apple_platform_suffix}")
|
|
||||||
elseif(CMAKE_OSX_SYSROOT MATCHES Watch)
|
|
||||||
set(_OS_SDK "watch${apple_platform_suffix}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if(DEFINED _OS_SDK)
|
|
||||||
message(STATUS "CMake-Conan: cmake_osx_sysroot=${CMAKE_OSX_SYSROOT}")
|
|
||||||
set(${OS_SDK} ${_OS_SDK} PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
if(DEFINED CMAKE_OSX_DEPLOYMENT_TARGET)
|
|
||||||
message(STATUS "CMake-Conan: cmake_osx_deployment_target=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
|
||||||
set(${OS_VERSION} ${CMAKE_OSX_DEPLOYMENT_TARGET} PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
function(detect_arch ARCH)
|
|
||||||
# CMAKE_OSX_ARCHITECTURES can contain multiple architectures, but Conan only supports one.
|
|
||||||
# Therefore this code only finds one. If the recipes support multiple architectures, the
|
|
||||||
# build will work. Otherwise, there will be a linker error for the missing architecture(s).
|
|
||||||
if(DEFINED CMAKE_OSX_ARCHITECTURES)
|
|
||||||
string(REPLACE " " ";" apple_arch_list "${CMAKE_OSX_ARCHITECTURES}")
|
|
||||||
list(LENGTH apple_arch_list apple_arch_count)
|
|
||||||
if(apple_arch_count GREATER 1)
|
|
||||||
message(WARNING "CMake-Conan: Multiple architectures detected, this will only work if Conan recipe(s) produce fat binaries.")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64" OR CMAKE_OSX_ARCHITECTURES MATCHES arm64)
|
|
||||||
set(_ARCH armv8)
|
|
||||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7-a|armv7l" OR CMAKE_OSX_ARCHITECTURES MATCHES armv7)
|
|
||||||
set(_ARCH armv7)
|
|
||||||
elseif(CMAKE_OSX_ARCHITECTURES MATCHES armv7s)
|
|
||||||
set(_ARCH armv7s)
|
|
||||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686" OR CMAKE_OSX_ARCHITECTURES MATCHES i386)
|
|
||||||
set(_ARCH x86)
|
|
||||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|amd64|x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES x86_64)
|
|
||||||
set(_ARCH x86_64)
|
|
||||||
endif()
|
|
||||||
message(STATUS "CMake-Conan: cmake_system_processor=${_ARCH}")
|
|
||||||
set(${ARCH} ${_ARCH} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
function(detect_cxx_standard CXX_STANDARD)
|
|
||||||
set(${CXX_STANDARD} ${CMAKE_CXX_STANDARD} PARENT_SCOPE)
|
|
||||||
if(CMAKE_CXX_EXTENSIONS)
|
|
||||||
set(${CXX_STANDARD} "gnu${CMAKE_CXX_STANDARD}" PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
macro(detect_gnu_libstdcxx)
|
|
||||||
# _CONAN_IS_GNU_LIBSTDCXX true if GNU libstdc++
|
|
||||||
check_cxx_source_compiles("
|
|
||||||
#include <cstddef>
|
|
||||||
#if !defined(__GLIBCXX__) && !defined(__GLIBCPP__)
|
|
||||||
static_assert(false);
|
|
||||||
#endif
|
|
||||||
int main(){}" _CONAN_IS_GNU_LIBSTDCXX)
|
|
||||||
|
|
||||||
# _CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI true if C++11 ABI
|
|
||||||
check_cxx_source_compiles("
|
|
||||||
#include <string>
|
|
||||||
static_assert(sizeof(std::string) != sizeof(void*), \"using libstdc++\");
|
|
||||||
int main () {}" _CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI)
|
|
||||||
|
|
||||||
set(_CONAN_GNU_LIBSTDCXX_SUFFIX "")
|
|
||||||
if(_CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI)
|
|
||||||
set(_CONAN_GNU_LIBSTDCXX_SUFFIX "11")
|
|
||||||
endif()
|
|
||||||
unset (_CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI)
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
macro(detect_libcxx)
|
|
||||||
# _CONAN_IS_LIBCXX true if LLVM libc++
|
|
||||||
check_cxx_source_compiles("
|
|
||||||
#include <cstddef>
|
|
||||||
#if !defined(_LIBCPP_VERSION)
|
|
||||||
static_assert(false);
|
|
||||||
#endif
|
|
||||||
int main(){}" _CONAN_IS_LIBCXX)
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
|
|
||||||
function(detect_lib_cxx OS LIB_CXX)
|
|
||||||
if(${OS} STREQUAL "Android")
|
|
||||||
message(STATUS "CMake-Conan: android_stl=${ANDROID_STL}")
|
|
||||||
set(${LIB_CXX} ${ANDROID_STL} PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(CheckCXXSourceCompiles)
|
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
|
||||||
detect_gnu_libstdcxx()
|
|
||||||
set(${LIB_CXX} "libstdc++${_CONAN_GNU_LIBSTDCXX_SUFFIX}" PARENT_SCOPE)
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
|
|
||||||
set(${LIB_CXX} "libc++" PARENT_SCOPE)
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
|
|
||||||
# Check for libc++
|
|
||||||
detect_libcxx()
|
|
||||||
if(_CONAN_IS_LIBCXX)
|
|
||||||
set(${LIB_CXX} "libc++" PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Check for libstdc++
|
|
||||||
detect_gnu_libstdcxx()
|
|
||||||
if(_CONAN_IS_GNU_LIBSTDCXX)
|
|
||||||
set(${LIB_CXX} "libstdc++${_CONAN_GNU_LIBSTDCXX_SUFFIX}" PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# TODO: it would be an error if we reach this point
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|
||||||
# Do nothing - compiler.runtime and compiler.runtime_type
|
|
||||||
# should be handled separately: https://github.com/conan-io/cmake-conan/pull/516
|
|
||||||
return()
|
|
||||||
else()
|
|
||||||
# TODO: unable to determine, ask user to provide a full profile file instead
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
function(detect_compiler COMPILER COMPILER_VERSION COMPILER_RUNTIME COMPILER_RUNTIME_TYPE)
|
|
||||||
if(DEFINED CMAKE_CXX_COMPILER_ID)
|
|
||||||
set(_COMPILER ${CMAKE_CXX_COMPILER_ID})
|
|
||||||
set(_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION})
|
|
||||||
else()
|
|
||||||
if(NOT DEFINED CMAKE_C_COMPILER_ID)
|
|
||||||
message(FATAL_ERROR "C or C++ compiler not defined")
|
|
||||||
endif()
|
|
||||||
set(_COMPILER ${CMAKE_C_COMPILER_ID})
|
|
||||||
set(_COMPILER_VERSION ${CMAKE_C_COMPILER_VERSION})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message(STATUS "CMake-Conan: CMake compiler=${_COMPILER}")
|
|
||||||
message(STATUS "CMake-Conan: CMake compiler version=${_COMPILER_VERSION}")
|
|
||||||
|
|
||||||
if(_COMPILER MATCHES MSVC)
|
|
||||||
set(_COMPILER "msvc")
|
|
||||||
string(SUBSTRING ${MSVC_VERSION} 0 3 _COMPILER_VERSION)
|
|
||||||
# Configure compiler.runtime and compiler.runtime_type settings for MSVC
|
|
||||||
if(CMAKE_MSVC_RUNTIME_LIBRARY)
|
|
||||||
set(_KNOWN_MSVC_RUNTIME_VALUES "")
|
|
||||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded MultiThreadedDLL)
|
|
||||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreadedDebug MultiThreadedDebugDLL)
|
|
||||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded$<$<CONFIG:Debug>:Debug> MultiThreaded$<$<CONFIG:Debug>:Debug>DLL)
|
|
||||||
|
|
||||||
# only accept the 6 possible values, otherwise we don't don't know to map this
|
|
||||||
if(NOT CMAKE_MSVC_RUNTIME_LIBRARY IN_LIST _KNOWN_MSVC_RUNTIME_VALUES)
|
|
||||||
message(FATAL_ERROR "CMake-Conan: unable to map MSVC runtime: ${CMAKE_MSVC_RUNTIME_LIBRARY} to Conan settings")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Runtime is "dynamic" in all cases if it ends in DLL
|
|
||||||
if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES ".*DLL$")
|
|
||||||
set(_COMPILER_RUNTIME "dynamic")
|
|
||||||
else()
|
|
||||||
set(_COMPILER_RUNTIME "static")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Only define compiler.runtime_type when explicitly requested
|
|
||||||
# If a generator expression is used, let Conan handle it conditional on build_type
|
|
||||||
get_property(_IS_MULTI_CONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
|
||||||
if(NOT CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "<CONFIG:Debug>:Debug>")
|
|
||||||
if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "Debug")
|
|
||||||
set(_COMPILER_RUNTIME_TYPE "Debug")
|
|
||||||
else()
|
|
||||||
set(_COMPILER_RUNTIME_TYPE "Release")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
unset(_KNOWN_MSVC_RUNTIME_VALUES)
|
|
||||||
unset(_IS_MULTI_CONFIG_GENERATOR)
|
|
||||||
endif()
|
|
||||||
elseif(_COMPILER MATCHES AppleClang)
|
|
||||||
set(_COMPILER "apple-clang")
|
|
||||||
string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION})
|
|
||||||
list(GET VERSION_LIST 0 _COMPILER_VERSION)
|
|
||||||
elseif(_COMPILER MATCHES Clang)
|
|
||||||
set(_COMPILER "clang")
|
|
||||||
string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION})
|
|
||||||
list(GET VERSION_LIST 0 _COMPILER_VERSION)
|
|
||||||
elseif(_COMPILER MATCHES GNU)
|
|
||||||
set(_COMPILER "gcc")
|
|
||||||
string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION})
|
|
||||||
list(GET VERSION_LIST 0 _COMPILER_VERSION)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message(STATUS "CMake-Conan: [settings] compiler=${_COMPILER}")
|
|
||||||
message(STATUS "CMake-Conan: [settings] compiler.version=${_COMPILER_VERSION}")
|
|
||||||
if (_COMPILER_RUNTIME)
|
|
||||||
message(STATUS "CMake-Conan: [settings] compiler.runtime=${_COMPILER_RUNTIME}")
|
|
||||||
endif()
|
|
||||||
if (_COMPILER_RUNTIME_TYPE)
|
|
||||||
message(STATUS "CMake-Conan: [settings] compiler.runtime_type=${_COMPILER_RUNTIME_TYPE}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(${COMPILER} ${_COMPILER} PARENT_SCOPE)
|
|
||||||
set(${COMPILER_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE)
|
|
||||||
set(${COMPILER_RUNTIME} ${_COMPILER_RUNTIME} PARENT_SCOPE)
|
|
||||||
set(${COMPILER_RUNTIME_TYPE} ${_COMPILER_RUNTIME_TYPE} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(detect_build_type BUILD_TYPE)
|
|
||||||
get_property(_MULTICONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
|
||||||
if(NOT _MULTICONFIG_GENERATOR)
|
|
||||||
# Only set when we know we are in a single-configuration generator
|
|
||||||
# Note: we may want to fail early if `CMAKE_BUILD_TYPE` is not defined
|
|
||||||
set(${BUILD_TYPE} ${CMAKE_BUILD_TYPE} PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
macro(append_compiler_executables_configuration)
|
|
||||||
set(_conan_c_compiler "")
|
|
||||||
set(_conan_cpp_compiler "")
|
|
||||||
if(CMAKE_C_COMPILER)
|
|
||||||
set(_conan_c_compiler "\"c\":\"${CMAKE_C_COMPILER}\",")
|
|
||||||
else()
|
|
||||||
message(WARNING "CMake-Conan: The C compiler is not defined. "
|
|
||||||
"Please define CMAKE_C_COMPILER or enable the C language.")
|
|
||||||
endif()
|
|
||||||
if(CMAKE_CXX_COMPILER)
|
|
||||||
set(_conan_cpp_compiler "\"cpp\":\"${CMAKE_CXX_COMPILER}\"")
|
|
||||||
else()
|
|
||||||
message(WARNING "CMake-Conan: The C++ compiler is not defined. "
|
|
||||||
"Please define CMAKE_CXX_COMPILER or enable the C++ language.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(APPEND PROFILE "tools.build:compiler_executables={${_conan_c_compiler}${_conan_cpp_compiler}}\n")
|
|
||||||
unset(_conan_c_compiler)
|
|
||||||
unset(_conan_cpp_compiler)
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
|
|
||||||
function(detect_host_profile output_file)
|
|
||||||
detect_os(MYOS MYOS_API_LEVEL MYOS_SDK MYOS_SUBSYSTEM MYOS_VERSION)
|
|
||||||
detect_arch(MYARCH)
|
|
||||||
detect_compiler(MYCOMPILER MYCOMPILER_VERSION MYCOMPILER_RUNTIME MYCOMPILER_RUNTIME_TYPE)
|
|
||||||
detect_cxx_standard(MYCXX_STANDARD)
|
|
||||||
detect_lib_cxx(MYOS MYLIB_CXX)
|
|
||||||
detect_build_type(MYBUILD_TYPE)
|
|
||||||
|
|
||||||
set(PROFILE "")
|
|
||||||
string(APPEND PROFILE "[settings]\n")
|
|
||||||
if(MYARCH)
|
|
||||||
string(APPEND PROFILE arch=${MYARCH} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYOS)
|
|
||||||
string(APPEND PROFILE os=${MYOS} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYOS_API_LEVEL)
|
|
||||||
string(APPEND PROFILE os.api_level=${MYOS_API_LEVEL} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYOS_VERSION)
|
|
||||||
string(APPEND PROFILE os.version=${MYOS_VERSION} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYOS_SDK)
|
|
||||||
string(APPEND PROFILE os.sdk=${MYOS_SDK} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYOS_SUBSYSTEM)
|
|
||||||
string(APPEND PROFILE os.subsystem=${MYOS_SUBSYSTEM} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYCOMPILER)
|
|
||||||
string(APPEND PROFILE compiler=${MYCOMPILER} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYCOMPILER_VERSION)
|
|
||||||
string(APPEND PROFILE compiler.version=${MYCOMPILER_VERSION} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYCOMPILER_RUNTIME)
|
|
||||||
string(APPEND PROFILE compiler.runtime=${MYCOMPILER_RUNTIME} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYCOMPILER_RUNTIME_TYPE)
|
|
||||||
string(APPEND PROFILE compiler.runtime_type=${MYCOMPILER_RUNTIME_TYPE} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYCXX_STANDARD)
|
|
||||||
string(APPEND PROFILE compiler.cppstd=${MYCXX_STANDARD} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYLIB_CXX)
|
|
||||||
string(APPEND PROFILE compiler.libcxx=${MYLIB_CXX} "\n")
|
|
||||||
endif()
|
|
||||||
if(MYBUILD_TYPE)
|
|
||||||
string(APPEND PROFILE "build_type=${MYBUILD_TYPE}\n")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT DEFINED output_file)
|
|
||||||
set(_FN "${CMAKE_BINARY_DIR}/profile")
|
|
||||||
else()
|
|
||||||
set(_FN ${output_file})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(APPEND PROFILE "[conf]\n")
|
|
||||||
string(APPEND PROFILE "tools.cmake.cmaketoolchain:generator=${CMAKE_GENERATOR}\n")
|
|
||||||
|
|
||||||
# propagate compilers via profile
|
|
||||||
append_compiler_executables_configuration()
|
|
||||||
|
|
||||||
if(${MYOS} STREQUAL "Android")
|
|
||||||
string(APPEND PROFILE "tools.android:ndk_path=${CMAKE_ANDROID_NDK}\n")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message(STATUS "CMake-Conan: Creating profile ${_FN}")
|
|
||||||
file(WRITE ${_FN} ${PROFILE})
|
|
||||||
message(STATUS "CMake-Conan: Profile: \n${PROFILE}")
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
function(conan_profile_detect_default)
|
|
||||||
message(STATUS "CMake-Conan: Checking if a default profile exists")
|
|
||||||
execute_process(COMMAND ${CONAN_COMMAND} profile path default
|
|
||||||
RESULT_VARIABLE return_code
|
|
||||||
OUTPUT_VARIABLE conan_stdout
|
|
||||||
ERROR_VARIABLE conan_stderr
|
|
||||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
|
||||||
ECHO_OUTPUT_VARIABLE
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
if(NOT ${return_code} EQUAL "0")
|
|
||||||
message(STATUS "CMake-Conan: The default profile doesn't exist, detecting it.")
|
|
||||||
execute_process(COMMAND ${CONAN_COMMAND} profile detect
|
|
||||||
RESULT_VARIABLE return_code
|
|
||||||
OUTPUT_VARIABLE conan_stdout
|
|
||||||
ERROR_VARIABLE conan_stderr
|
|
||||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
|
||||||
ECHO_OUTPUT_VARIABLE
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
function(conan_install)
|
|
||||||
cmake_parse_arguments(ARGS CONAN_ARGS ${ARGN})
|
|
||||||
set(CONAN_OUTPUT_FOLDER ${CMAKE_BINARY_DIR}/conan)
|
|
||||||
# Invoke "conan install" with the provided arguments
|
|
||||||
set(CONAN_ARGS ${CONAN_ARGS} -of=${CONAN_OUTPUT_FOLDER})
|
|
||||||
message(STATUS "CMake-Conan: conan install ${CMAKE_SOURCE_DIR} ${CONAN_ARGS} ${ARGN}")
|
|
||||||
execute_process(COMMAND ${CONAN_COMMAND} install ${CMAKE_SOURCE_DIR} ${CONAN_ARGS} ${ARGN} --format=json
|
|
||||||
RESULT_VARIABLE return_code
|
|
||||||
OUTPUT_VARIABLE conan_stdout
|
|
||||||
ERROR_VARIABLE conan_stderr
|
|
||||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
if(NOT "${return_code}" STREQUAL "0")
|
|
||||||
message(FATAL_ERROR "Conan install failed='${return_code}'")
|
|
||||||
else()
|
|
||||||
# the files are generated in a folder that depends on the layout used, if
|
|
||||||
# one is specified, but we don't know a priori where this is.
|
|
||||||
# TODO: this can be made more robust if Conan can provide this in the json output
|
|
||||||
string(JSON CONAN_GENERATORS_FOLDER GET ${conan_stdout} graph nodes 0 generators_folder)
|
|
||||||
# message("conan stdout: ${conan_stdout}")
|
|
||||||
message(STATUS "CMake-Conan: CONAN_GENERATORS_FOLDER=${CONAN_GENERATORS_FOLDER}")
|
|
||||||
set_property(GLOBAL PROPERTY CONAN_GENERATORS_FOLDER "${CONAN_GENERATORS_FOLDER}")
|
|
||||||
# reconfigure on conanfile changes
|
|
||||||
string(JSON CONANFILE GET ${conan_stdout} graph nodes 0 label)
|
|
||||||
message(STATUS "CMake-Conan: CONANFILE=${CMAKE_SOURCE_DIR}/${CONANFILE}")
|
|
||||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/${CONANFILE}")
|
|
||||||
# success
|
|
||||||
set_property(GLOBAL PROPERTY CONAN_INSTALL_SUCCESS TRUE)
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
function(conan_get_version conan_command conan_current_version)
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${conan_command} --version
|
|
||||||
OUTPUT_VARIABLE conan_output
|
|
||||||
RESULT_VARIABLE conan_result
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
if(conan_result)
|
|
||||||
message(FATAL_ERROR "CMake-Conan: Error when trying to run Conan")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" conan_version ${conan_output})
|
|
||||||
set(${conan_current_version} ${conan_version} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
function(conan_version_check)
|
|
||||||
set(options )
|
|
||||||
set(oneValueArgs MINIMUM CURRENT)
|
|
||||||
set(multiValueArgs )
|
|
||||||
cmake_parse_arguments(CONAN_VERSION_CHECK
|
|
||||||
"${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
||||||
|
|
||||||
if(NOT CONAN_VERSION_CHECK_MINIMUM)
|
|
||||||
message(FATAL_ERROR "CMake-Conan: Required parameter MINIMUM not set!")
|
|
||||||
endif()
|
|
||||||
if(NOT CONAN_VERSION_CHECK_CURRENT)
|
|
||||||
message(FATAL_ERROR "CMake-Conan: Required parameter CURRENT not set!")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CONAN_VERSION_CHECK_CURRENT VERSION_LESS CONAN_VERSION_CHECK_MINIMUM)
|
|
||||||
message(FATAL_ERROR "CMake-Conan: Conan version must be ${CONAN_VERSION_CHECK_MINIMUM} or later")
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
macro(construct_profile_argument argument_variable profile_list)
|
|
||||||
set(${argument_variable} "")
|
|
||||||
if("${profile_list}" STREQUAL "CONAN_HOST_PROFILE")
|
|
||||||
set(_arg_flag "--profile:host=")
|
|
||||||
elseif("${profile_list}" STREQUAL "CONAN_BUILD_PROFILE")
|
|
||||||
set(_arg_flag "--profile:build=")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(_profile_list "${${profile_list}}")
|
|
||||||
list(TRANSFORM _profile_list REPLACE "auto-cmake" "${CMAKE_BINARY_DIR}/conan_host_profile")
|
|
||||||
list(TRANSFORM _profile_list PREPEND ${_arg_flag})
|
|
||||||
set(${argument_variable} ${_profile_list})
|
|
||||||
|
|
||||||
unset(_arg_flag)
|
|
||||||
unset(_profile_list)
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
|
|
||||||
macro(conan_provide_dependency method package_name)
|
|
||||||
set_property(GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED TRUE)
|
|
||||||
get_property(CONAN_INSTALL_SUCCESS GLOBAL PROPERTY CONAN_INSTALL_SUCCESS)
|
|
||||||
if(NOT CONAN_INSTALL_SUCCESS)
|
|
||||||
find_program(CONAN_COMMAND "conan" REQUIRED)
|
|
||||||
conan_get_version(${CONAN_COMMAND} CONAN_CURRENT_VERSION)
|
|
||||||
conan_version_check(MINIMUM ${CONAN_MINIMUM_VERSION} CURRENT ${CONAN_CURRENT_VERSION})
|
|
||||||
message(STATUS "CMake-Conan: first find_package() found. Installing dependencies with Conan")
|
|
||||||
if("default" IN_LIST CONAN_HOST_PROFILE OR "default" IN_LIST CONAN_BUILD_PROFILE)
|
|
||||||
conan_profile_detect_default()
|
|
||||||
endif()
|
|
||||||
if("auto-cmake" IN_LIST CONAN_HOST_PROFILE)
|
|
||||||
detect_host_profile(${CMAKE_BINARY_DIR}/conan_host_profile)
|
|
||||||
endif()
|
|
||||||
construct_profile_argument(_host_profile_flags CONAN_HOST_PROFILE)
|
|
||||||
construct_profile_argument(_build_profile_flags CONAN_BUILD_PROFILE)
|
|
||||||
get_property(_MULTICONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
|
||||||
if(NOT _MULTICONFIG_GENERATOR)
|
|
||||||
message(STATUS "CMake-Conan: Installing single configuration ${CMAKE_BUILD_TYPE}")
|
|
||||||
conan_install(${_host_profile_flags} ${_build_profile_flags} --build=missing -g CMakeDeps)
|
|
||||||
else()
|
|
||||||
message(STATUS "CMake-Conan: Installing both Debug and Release")
|
|
||||||
conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Release --build=missing -g CMakeDeps)
|
|
||||||
conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Debug --build=missing -g CMakeDeps)
|
|
||||||
endif()
|
|
||||||
unset(_MULTICONFIG_GENERATOR)
|
|
||||||
else()
|
|
||||||
message(STATUS "CMake-Conan: find_package(${ARGV1}) found, 'conan install' already ran")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
get_property(CONAN_GENERATORS_FOLDER GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
|
|
||||||
|
|
||||||
# Ensure that we consider Conan-provided packages ahead of any other,
|
|
||||||
# irrespective of other settings that modify the search order or search paths
|
|
||||||
# This follows the guidelines from the find_package documentation
|
|
||||||
# (https://cmake.org/cmake/help/latest/command/find_package.html):
|
|
||||||
# find_package (<PackageName> PATHS paths... NO_DEFAULT_PATH)
|
|
||||||
# find_package (<PackageName>)
|
|
||||||
|
|
||||||
# Filter out `REQUIRED` from the argument list, as the first call may fail
|
|
||||||
set(_find_args "${ARGN}")
|
|
||||||
list(REMOVE_ITEM _find_args "REQUIRED")
|
|
||||||
if(NOT "MODULE" IN_LIST _find_args)
|
|
||||||
find_package(${package_name} ${_find_args} BYPASS_PROVIDER PATHS "${CONAN_GENERATORS_FOLDER}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Invoke find_package a second time - if the first call succeeded,
|
|
||||||
# this will simply reuse the result. If not, fall back to CMake default search
|
|
||||||
# behaviour, also allowing modules to be searched.
|
|
||||||
set(_cmake_module_path_orig "${CMAKE_MODULE_PATH}")
|
|
||||||
list(PREPEND CMAKE_MODULE_PATH "${CONAN_GENERATORS_FOLDER}")
|
|
||||||
if(NOT ${package_name}_FOUND)
|
|
||||||
find_package(${package_name} ${ARGN} BYPASS_PROVIDER)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${_cmake_module_path_orig}")
|
|
||||||
unset(_find_args)
|
|
||||||
unset(_cmake_module_path_orig)
|
|
||||||
unset(_host_profile_flags)
|
|
||||||
unset(_build_profile_flags)
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
|
|
||||||
cmake_language(
|
|
||||||
SET_DEPENDENCY_PROVIDER conan_provide_dependency
|
|
||||||
SUPPORTED_METHODS FIND_PACKAGE
|
|
||||||
)
|
|
||||||
|
|
||||||
macro(conan_provide_dependency_check)
|
|
||||||
set(_CONAN_PROVIDE_DEPENDENCY_INVOKED FALSE)
|
|
||||||
get_property(_CONAN_PROVIDE_DEPENDENCY_INVOKED GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED)
|
|
||||||
if(NOT _CONAN_PROVIDE_DEPENDENCY_INVOKED)
|
|
||||||
message(WARNING "Conan is correctly configured as dependency provider, "
|
|
||||||
"but Conan has not been invoked. Please add at least one "
|
|
||||||
"call to `find_package()`.")
|
|
||||||
if(DEFINED CONAN_COMMAND)
|
|
||||||
# supress warning in case `CONAN_COMMAND` was specified but unused.
|
|
||||||
set(_CONAN_COMMAND ${CONAN_COMMAND})
|
|
||||||
unset(_CONAN_COMMAND)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
unset(_CONAN_PROVIDE_DEPENDENCY_INVOKED)
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
# Add a deferred call at the end of processing the top-level directory
|
|
||||||
# to check if the dependency provider was invoked at all.
|
|
||||||
cmake_language(DEFER DIRECTORY "${CMAKE_SOURCE_DIR}" CALL conan_provide_dependency_check)
|
|
||||||
|
|
||||||
# Configurable variables for Conan profiles
|
|
||||||
set(CONAN_HOST_PROFILE "default;auto-cmake" CACHE STRING "Conan host profile")
|
|
||||||
set(CONAN_BUILD_PROFILE "default" CACHE STRING "Conan build profile")
|
|
|
@ -1,7 +0,0 @@
|
||||||
# This file is managed by Conan, contents will be overwritten.
|
|
||||||
# To keep your changes, remove these comment lines, but the plugin won't be able to modify your requirements
|
|
||||||
|
|
||||||
requirements:
|
|
||||||
- "ncurses/6.4"
|
|
||||||
- "libcheck/0.15.2"
|
|
||||||
- "log.c/cci.20200620"
|
|
23
conanfile.py
23
conanfile.py
|
@ -1,23 +0,0 @@
|
||||||
# This file is managed by Conan, contents will be overwritten.
|
|
||||||
# To keep your changes, remove these comment lines, but the plugin won't be able to modify your requirements
|
|
||||||
|
|
||||||
from conan import ConanFile
|
|
||||||
from conan.tools.cmake import cmake_layout, CMakeToolchain
|
|
||||||
|
|
||||||
class ConanApplication(ConanFile):
|
|
||||||
package_type = "application"
|
|
||||||
settings = "os", "compiler", "build_type", "arch"
|
|
||||||
generators = "CMakeDeps"
|
|
||||||
|
|
||||||
def layout(self):
|
|
||||||
cmake_layout(self)
|
|
||||||
|
|
||||||
def generate(self):
|
|
||||||
tc = CMakeToolchain(self)
|
|
||||||
tc.user_presets_path = False
|
|
||||||
tc.generate()
|
|
||||||
|
|
||||||
def requirements(self):
|
|
||||||
requirements = self.conan_data.get('requirements', [])
|
|
||||||
for requirement in requirements:
|
|
||||||
self.requires(requirement)
|
|
|
@ -1,10 +1,6 @@
|
||||||
add_library(CPU
|
set(HEADERS cpu.h decoding.h memory.h op.h)
|
||||||
cpu.c
|
set(SOURCE cpu.c decoding.c memory.c op.c)
|
||||||
op.c
|
|
||||||
memory.c
|
|
||||||
cpu.h
|
|
||||||
decoding.c
|
|
||||||
decoding.h)
|
|
||||||
|
|
||||||
find_package(log.c)
|
add_library(nes_cpu ${SOURCE} ${HEADERS})
|
||||||
target_link_libraries(CPU log.c::log.c)
|
|
||||||
|
target_link_libraries(nes_cpu log.c)
|
|
@ -1,4 +1,4 @@
|
||||||
#include <log.h>
|
//#include "log.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../include/cpu.h"
|
#include "../include/cpu.h"
|
||||||
|
@ -6,6 +6,7 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "op.h"
|
#include "op.h"
|
||||||
#include "decoding.h"
|
#include "decoding.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* =====================================================================================
|
* =====================================================================================
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "decoding.h"
|
#include "decoding.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <log.h>
|
#include "log.h"
|
||||||
|
|
||||||
address decode_operand_addr(System *system, AddressingMode addr_mode, bool *page_crossing) {
|
address decode_operand_addr(System *system, AddressingMode addr_mode, bool *page_crossing) {
|
||||||
CPU registers = system->cpu;
|
CPU registers = system->cpu;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <log.h>
|
#include "log.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "../include/rom.h"
|
#include "../include/rom.h"
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
add_library(DEBUG
|
set(HEADERS cpu_view.h cursor.h debugger.h dialog.h keys.h memory_view.h program_view.h window.h)
|
||||||
debugger.c
|
set(SOURCE cpu_view.c cursor.c debugger.c dialog.c memory_view.c program_view.c window.c)
|
||||||
memory_view.c
|
|
||||||
dialog.c
|
|
||||||
program_view.c
|
|
||||||
program_view.h
|
|
||||||
cursor.c
|
|
||||||
cursor.h
|
|
||||||
window.c
|
|
||||||
window.h
|
|
||||||
keys.h)
|
|
||||||
|
|
||||||
find_package(Curses)
|
add_library(nes_debugger ${HEADERS} ${SOURCE})
|
||||||
|
|
||||||
target_link_libraries(DEBUG Curses::Curses)
|
target_link_libraries(nes_debugger ncurses panel)
|
|
@ -0,0 +1,5 @@
|
||||||
|
//
|
||||||
|
// Created by william on 4/30/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "cpu_view.h"
|
|
@ -0,0 +1,8 @@
|
||||||
|
//
|
||||||
|
// Created by william on 4/30/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef NESEMULATOR_CPU_VIEW_H
|
||||||
|
#define NESEMULATOR_CPU_VIEW_H
|
||||||
|
|
||||||
|
#endif //NESEMULATOR_CPU_VIEW_H
|
|
@ -0,0 +1,3 @@
|
||||||
|
project(log.c LANGUAGES C VERSION 0.1.0)
|
||||||
|
|
||||||
|
add_library(log.c src/log.h src/log.c)
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2020 rxi
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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 OR COPYRIGHT HOLDERS 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.
|
|
@ -0,0 +1,83 @@
|
||||||
|
# log.c
|
||||||
|
A simple logging library implemented in C99
|
||||||
|
|
||||||
|
![screenshot](https://cloud.githubusercontent.com/assets/3920290/23831970/a2415e96-0723-11e7-9886-f8f5d2de60fe.png)
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
**[log.c](src/log.c?raw=1)** and **[log.h](src/log.h?raw=1)** should be dropped
|
||||||
|
into an existing project and compiled along with it. The library provides 6
|
||||||
|
function-like macros for logging:
|
||||||
|
|
||||||
|
```c
|
||||||
|
log_trace(const char *fmt, ...);
|
||||||
|
log_debug(const char *fmt, ...);
|
||||||
|
log_info(const char *fmt, ...);
|
||||||
|
log_warn(const char *fmt, ...);
|
||||||
|
log_error(const char *fmt, ...);
|
||||||
|
log_fatal(const char *fmt, ...);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each function takes a printf format string followed by additional arguments:
|
||||||
|
|
||||||
|
```c
|
||||||
|
log_trace("Hello %s", "world")
|
||||||
|
```
|
||||||
|
|
||||||
|
Resulting in a line with the given format printed to stderr:
|
||||||
|
|
||||||
|
```
|
||||||
|
20:18:26 TRACE src/main.c:11: Hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### log_set_quiet(bool enable)
|
||||||
|
Quiet-mode can be enabled by passing `true` to the `log_set_quiet()` function.
|
||||||
|
While this mode is enabled the library will not output anything to `stderr`, but
|
||||||
|
will continue to write to files and callbacks if any are set.
|
||||||
|
|
||||||
|
|
||||||
|
#### log_set_level(int level)
|
||||||
|
The current logging level can be set by using the `log_set_level()` function.
|
||||||
|
All logs below the given level will not be written to `stderr`. By default the
|
||||||
|
level is `LOG_TRACE`, such that nothing is ignored.
|
||||||
|
|
||||||
|
|
||||||
|
#### log_add_fp(FILE *fp, int level)
|
||||||
|
One or more file pointers where the log will be written can be provided to the
|
||||||
|
library by using the `log_add_fp()` function. The data written to the file
|
||||||
|
output is of the following format:
|
||||||
|
|
||||||
|
```
|
||||||
|
2047-03-11 20:18:26 TRACE src/main.c:11: Hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
Any messages below the given `level` are ignored. If the library failed to add a
|
||||||
|
file pointer a value less-than-zero is returned.
|
||||||
|
|
||||||
|
|
||||||
|
#### log_add_callback(log_LogFn fn, void *udata, int level)
|
||||||
|
One or more callback functions which are called with the log data can be
|
||||||
|
provided to the library by using the `log_add_callback()` function. A callback
|
||||||
|
function is passed a `log_Event` structure containing the `line` number,
|
||||||
|
`filename`, `fmt` string, `va` printf va\_list, `level` and the given `udata`.
|
||||||
|
|
||||||
|
|
||||||
|
#### log_set_lock(log_LockFn fn, void *udata)
|
||||||
|
If the log will be written to from multiple threads a lock function can be set.
|
||||||
|
The function is passed the boolean `true` if the lock should be acquired or
|
||||||
|
`false` if the lock should be released and the given `udata` value.
|
||||||
|
|
||||||
|
|
||||||
|
#### const char* log_level_string(int level)
|
||||||
|
Returns the name of the given log level as a string.
|
||||||
|
|
||||||
|
|
||||||
|
#### LOG_USE_COLOR
|
||||||
|
If the library is compiled with `-DLOG_USE_COLOR` ANSI color escape codes will
|
||||||
|
be used when printing.
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
This library is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the MIT license. See [LICENSE](LICENSE) for details.
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 rxi
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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 OR COPYRIGHT HOLDERS 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#define MAX_CALLBACKS 32
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
log_LogFn fn;
|
||||||
|
void *udata;
|
||||||
|
int level;
|
||||||
|
} Callback;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
void *udata;
|
||||||
|
log_LockFn lock;
|
||||||
|
int level;
|
||||||
|
bool quiet;
|
||||||
|
Callback callbacks[MAX_CALLBACKS];
|
||||||
|
} L;
|
||||||
|
|
||||||
|
|
||||||
|
static const char *level_strings[] = {
|
||||||
|
"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef LOG_USE_COLOR
|
||||||
|
static const char *level_colors[] = {
|
||||||
|
"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void stdout_callback(log_Event *ev) {
|
||||||
|
char buf[16];
|
||||||
|
buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
|
||||||
|
#ifdef LOG_USE_COLOR
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
|
||||||
|
buf, level_colors[ev->level], level_strings[ev->level],
|
||||||
|
ev->file, ev->line);
|
||||||
|
#else
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %-5s %s:%d: ",
|
||||||
|
buf, level_strings[ev->level], ev->file, ev->line);
|
||||||
|
#endif
|
||||||
|
vfprintf(ev->udata, ev->fmt, ev->ap);
|
||||||
|
fprintf(ev->udata, "\n");
|
||||||
|
fflush(ev->udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void file_callback(log_Event *ev) {
|
||||||
|
char buf[64];
|
||||||
|
buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %-5s %s:%d: ",
|
||||||
|
buf, level_strings[ev->level], ev->file, ev->line);
|
||||||
|
vfprintf(ev->udata, ev->fmt, ev->ap);
|
||||||
|
fprintf(ev->udata, "\n");
|
||||||
|
fflush(ev->udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void lock(void) {
|
||||||
|
if (L.lock) { L.lock(true, L.udata); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void unlock(void) {
|
||||||
|
if (L.lock) { L.lock(false, L.udata); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* log_level_string(int level) {
|
||||||
|
return level_strings[level];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_set_lock(log_LockFn fn, void *udata) {
|
||||||
|
L.lock = fn;
|
||||||
|
L.udata = udata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_set_level(int level) {
|
||||||
|
L.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_set_quiet(bool enable) {
|
||||||
|
L.quiet = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int log_add_callback(log_LogFn fn, void *udata, int level) {
|
||||||
|
for (int i = 0; i < MAX_CALLBACKS; i++) {
|
||||||
|
if (!L.callbacks[i].fn) {
|
||||||
|
L.callbacks[i] = (Callback) { fn, udata, level };
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int log_add_fp(FILE *fp, int level) {
|
||||||
|
return log_add_callback(file_callback, fp, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void init_event(log_Event *ev, void *udata) {
|
||||||
|
if (!ev->time) {
|
||||||
|
time_t t = time(NULL);
|
||||||
|
ev->time = localtime(&t);
|
||||||
|
}
|
||||||
|
ev->udata = udata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_log(int level, const char *file, int line, const char *fmt, ...) {
|
||||||
|
log_Event ev = {
|
||||||
|
.fmt = fmt,
|
||||||
|
.file = file,
|
||||||
|
.line = line,
|
||||||
|
.level = level,
|
||||||
|
};
|
||||||
|
|
||||||
|
lock();
|
||||||
|
|
||||||
|
if (!L.quiet && level >= L.level) {
|
||||||
|
init_event(&ev, stderr);
|
||||||
|
va_start(ev.ap, fmt);
|
||||||
|
stdout_callback(&ev);
|
||||||
|
va_end(ev.ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
|
||||||
|
Callback *cb = &L.callbacks[i];
|
||||||
|
if (level >= cb->level) {
|
||||||
|
init_event(&ev, cb->udata);
|
||||||
|
va_start(ev.ap, fmt);
|
||||||
|
cb->fn(&ev);
|
||||||
|
va_end(ev.ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2020 rxi
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the MIT license. See `log.c` for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOG_H
|
||||||
|
#define LOG_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define LOG_VERSION "0.1.0"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
va_list ap;
|
||||||
|
const char *fmt;
|
||||||
|
const char *file;
|
||||||
|
struct tm *time;
|
||||||
|
void *udata;
|
||||||
|
int line;
|
||||||
|
int level;
|
||||||
|
} log_Event;
|
||||||
|
|
||||||
|
typedef void (*log_LogFn)(log_Event *ev);
|
||||||
|
typedef void (*log_LockFn)(bool lock, void *udata);
|
||||||
|
|
||||||
|
enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
|
||||||
|
|
||||||
|
#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
|
||||||
|
const char* log_level_string(int level);
|
||||||
|
void log_set_lock(log_LockFn fn, void *udata);
|
||||||
|
void log_set_level(int level);
|
||||||
|
void log_set_quiet(bool enable);
|
||||||
|
int log_add_callback(log_LogFn fn, void *udata, int level);
|
||||||
|
int log_add_fp(FILE *fp, int level);
|
||||||
|
|
||||||
|
void log_log(int level, const char *file, int line, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif
|
2
main.c
2
main.c
|
@ -16,7 +16,7 @@
|
||||||
* =====================================================================================
|
* =====================================================================================
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <log.h>
|
#include "log.h"
|
||||||
#include "debugger/debugger.h"
|
#include "debugger/debugger.h"
|
||||||
|
|
||||||
#include "include/rom.h"
|
#include "include/rom.h"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
add_library(Mappers
|
set(SOURCE simple_mapper.c mappers.c)
|
||||||
simple_mapper.c
|
|
||||||
mappers.c)
|
|
||||||
|
|
||||||
find_package(log.c)
|
add_library(nes_mappers ${SOURCE})
|
||||||
target_link_libraries(Mappers log.c::log.c)
|
|
||||||
|
target_link_libraries(nes_mappers log.c)
|
|
@ -2,7 +2,7 @@
|
||||||
// Created by william on 10/15/23.
|
// Created by william on 10/15/23.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <log.h>
|
#include "log.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "../include/mapper.h"
|
#include "../include/mapper.h"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
add_library(PPU
|
set(SOURCE ppu.c)
|
||||||
ppu.c)
|
|
||||||
|
|
||||||
find_package(log.c)
|
add_library(nes_ppu ${SOURCE})
|
||||||
target_link_libraries(PPU log.c::log.c)
|
|
||||||
|
target_link_libraries(nes_ppu log.c)
|
|
@ -1,6 +1,5 @@
|
||||||
add_library(ROM
|
set(SOURCE rom.c ines.c)
|
||||||
rom.c
|
|
||||||
ines.c)
|
|
||||||
|
|
||||||
find_package(log.c)
|
add_library(nes_rom ${SOURCE})
|
||||||
target_link_libraries(ROM log.c::log.c)
|
|
||||||
|
target_link_libraries(nes_rom log.c)
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <log.h>
|
#include "log.h"
|
||||||
#include "../include/rom.h"
|
#include "../include/rom.h"
|
||||||
#include "../include/system.h"
|
#include "../include/system.h"
|
||||||
|
|
||||||
|
|
2
system.c
2
system.c
|
@ -7,7 +7,7 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <log.h>
|
#include "log.h"
|
||||||
|
|
||||||
void system_init(System *system) {
|
void system_init(System *system) {
|
||||||
byte *registers_base_addr = &system->ram[PPU_REGISTERS_BASE_ADDR];
|
byte *registers_base_addr = &system->ram[PPU_REGISTERS_BASE_ADDR];
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
add_library(UTILS
|
set(HEADERS linked_list.h)
|
||||||
linked_list.c)
|
set(SOURCE linked_list.c)
|
||||||
|
|
||||||
|
add_library(nes_utils ${HEADERS} ${SOURCE})
|
Loading…
Reference in New Issue