# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'mkmf' require 'rbconfig' require_relative '../lib/contrast/agent/version' # The mkmf.rb file uses all passed flags from Ruby configuration (RbConfig::CONFIG) on # Ruby build time. Problem with Clang and GCC is that it do not keep up with c89 and finds # error on including as not allowing inline variables. # # Ruby inlining is a C99 feature that is allowed to be used, because the Ruby configure script # can work around the absence of the inline feature with a simple #define: # # ifndef __cplusplus # define inline # endif # # There is difference between using c89 and gnu89, as the latter is extended version of the # 1989 standard allowing features like // comments for example. This makes the use of the # gnu not favorable since it will skip some checks and would make wholes in the c89 standard # support. # # We can directly append the CFLAGS we need with ENV variable used to create the makefile. # MAKEFILE_CONFIG is extension of the RbConfig::CONFIG used to build the Ruby itself. # So if we try to run c89 on clang it will brake because of detecting errors from external # library used - Ruby itself build with different standard as it seems. This means the # Ruby must be compiled beforehand with the compiler forced to C89. # # This makes the C dialect of choice to be gnu89 with strict pedantic warnings reported as errors, # and making the compiler configurable by flags: STANDARD_FLAGS = '-std=gnu89' CLANG = 'clang' # TODO: RUBY-999999 Add -pedantic flag, remove all warning flags and see to it that as many as possible become obsolete. # Note: Adding -pedantic could raise warnings, and we are not in control of that code. # e.g. error: '_Bool' is a C99 extension [-Werror,-Wc99-extensions] ; empty macros and etc. # # -Wno-int-conversion => Passing VALUEs as function args but required as unsigned long parameters. # -Werror => report all warnings as errors # -Wshorten-64-to-32 => is recognized by clang but not in gcc. # Use alternative if viable. [Wno-narrowing] # -Wno-maybe-uninitialized is used by clang but not gcc # # Note: Clang supports old style function definition e.g. void func () {} # but the gcc is not. # make sure to add parameters type => void func (void) {}. # All Changes must be tested against both clang and gcc. WARNING_FLAGS = %w[ -Wno-language-extension-token -Wno-incompatible-function-pointer-types -Wno-declaration-after-statement -Wno-variadic-macros -Wno-int-conversion -Wno-incompatible-pointer-types -Wno-narrowing ].freeze # rubocop:disable Security/Object/Freeze # Flags that are only recognized by gcc: GCC_FLAGS = %w[-Wno-maybe-uninitialized].freeze # rubocop:disable Security/Object/Freeze # Extend $CFLAGS passed directly to compiler in ruby mkmf def extend_cflags $CFLAGS += " #{ [STANDARD_FLAGS, WARNING_FLAGS].flatten.join(' ') }" # Extend with GCC specific flags: unless RbConfig::MAKEFILE_CONFIG['CC'].downcase.include?(CLANG) || RbConfig::MAKEFILE_CONFIG['CPP'].downcase.include?(CLANG) || RbConfig::CONFIG['CC'].downcase.include?(CLANG) $CFLAGS += " #{ GCC_FLAGS.flatten.join(' ') }" end end def make! create_makefile("#{ $TO_MAKE }/#{ $TO_MAKE }") end # ----------------------------------------------------------------------- # | MOVING CODE BELLOW THIS SECTION MAY BRAKE MAKEFILE. ORDER MATTERS! | # ---------------------------------------------------------------------- def ext_path # __dir__ is relative to the file you're reading. # this file you're reading is presently within $APP_ROOT/ext/. __dir__ end # We need to first build funchook which relies on ext_path method. This enables the require of # funchook.h file. Then we can pass CFLAGS and extend makefile flags and invoke make! require_relative './build_funchook' # Extended flags are mainly tested with clang and gcc. Experience with other compilers may vary. # To that end if something brakes on client side we must have a mechanism to go back to previous # non strict gnu89 standard and be able to maintain the build. # We can disable newly added changes with this setting CONTRAST_USE_C89=false. extend_cflags unless ENV['CONTRAST__USE_GNU89'] == 'false' # use same C compiler if set. RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC'] # Generate Makefile. make!