Skip to content

Commit

Permalink
Merge pull request dotnet#2108 from vargaz/mono-cmake-build
Browse files Browse the repository at this point in the history
Initial CMAKE build system support for Mono.
  • Loading branch information
vargaz authored Jan 24, 2020
2 parents e786610 + c62bd0b commit b10f41f
Show file tree
Hide file tree
Showing 13 changed files with 3,131 additions and 0 deletions.
219 changes: 219 additions & 0 deletions src/mono/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
cmake_minimum_required (VERSION 3.10)

project (mono)

include(GNUInstallDirs)
include(CheckIncludeFile)
include(CheckFunctionExists)
include(TestBigEndian)

set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
)

find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
endif()

function(append value)
foreach(variable ${ARGN})
set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
endforeach(variable)
endfunction()

# User options
include(options)
# Header/function checks
include(configure)

# FIXME:
set(VERSION "")

execute_process(
COMMAND grep ^MONO_CORLIB_VERSION= configure.ac
COMMAND cut -d = -f 2
OUTPUT_VARIABLE CORLIB_VERSION_OUT
)
if (CORLIB_VERSION_OUT STREQUAL "")
message(FATAL_ERROR)
endif()
string(STRIP "${CORLIB_VERSION_OUT}" MONO_CORLIB_VERSION_BASE)
set(MONO_CORLIB_VERSION "\"${MONO_CORLIB_VERSION_BASE}\"")

if (ENABLE_NETCORE)
set(DISABLE_REMOTING 1)
set(DISABLE_REFLECTION_EMIT_SAVE 1)
set(DISABLE_APPDOMAINS 1)
set(DISABLE_CLEANUP 1)
set(DISABLE_ASSEMBLY_REMAPPING 1)
set(DISABLE_SECURITY 1)
set(DISABLE_MDB 1)
set(DISABLE_COM 1)
set(DISABLE_GAC 1)
set(DISABLE_PERFCOUNTERS 1)
set(DISABLE_ATTACH 1)
set(DISABLE_DLLMAP 1)
else()
message(FATAL_ERROR "Building without -DENABLE_NETCORE=1 is not supported.")
endif()

#FIXME:
set(VERSION "\"\"")
set(DISABLED_FEATURES "\"\"")

if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
set (GCC 1)
endif ()

add_definitions(-g)
add_definitions(-DHAVE_CONFIG_H)
add_definitions(-D_THREAD_SAFE)

if (GCC)
add_definitions(-fPIC)
add_definitions(-DMONO_DLL_EXPORT)
add_definitions(-fvisibility=hidden)
endif()

set(USE_GCC_ATOMIC_OPS 1)
set(HAVE_CLASSIC_WINAPI_SUPPORT 1)
set(ENABLE_ILGEN 1)
set(HAVE_MOVING_COLLECTOR 1)
set(HAVE_CONC_GC_AS_DEFAULT 1)
set(MONO_INSIDE_RUNTIME 1)

######################################
# GCC CHECKS
######################################
if(GCC)
# We require C99 with some GNU extensions, e.g. `linux` macro
add_definitions(-std=gnu99)
# The runtime code does not respect ANSI C strict aliasing rules
append("-fno-strict-aliasing" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
# We rely on signed overflow to behave
append("-fwrapv" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)

set(WARNINGS "-Wall -Wunused -Wmissing-declarations -Wpointer-arith -Wno-cast-qual -Wwrite-strings -Wno-switch -Wno-switch-enum -Wno-unused-value -Wno-attributes -Qunused-arguments -Wno-unused-function -Wno-tautological-compare -Wno-parentheses-equality -Wno-self-assign -Wno-return-stack-address -Wno-constant-logical-operand -Wno-zero-length-array -Wmissing-prototypes -Wstrict-prototypes -Wnested-externs -Wno-format-zero-length")

set(WERROR "-Werror=incompatible-pointer-types -Werror=return-type -Werror-implicit-function-declaration")

append("${WARNINGS} ${WERROR}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
endif()

######################################
# HOST OS CHECKS
######################################

if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_definitions(-D_THREAD_SAFE)
set(HOST_DARWIN 1)
set(PTHREAD_POINTER_ID 1)
set(USE_MACH_SEMA 1)
else()
message(FATAL ERROR "")
endif()

######################################
# TARGET OS CHECKS
######################################

# FIXME:
set(TARGET_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")

if(TARGET_SYSTEM_NAME STREQUAL "Darwin")
set(TARGET_MACH 1)
set(TARGET_OSX 1)
set(RID_PREFIX "osx")
set(CORETARGETS "-p:TargetsUnix=true -p:TargetsOSX=true")
set(NETCORE_HOST_PLATFORM "macos")
else()
message(FATAL ERROR "")
endif()

######################################
# HOST ARCH CHECKS
######################################

if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(HOST_AMD64 1)
else()
message(FATAL ERROR "")
endif()

######################################
# TARGET ARCH CHECKS
######################################
# FIXME:
set(TARGET_ARCH "${CMAKE_SYSTEM_PROCESSOR}")

if(TARGET_ARCH STREQUAL "x86_64")
set(TARGET_AMD64 1)
set(MONO_ARCHITECTURE "\"amd64\"")
set(RID_SUFFIX "x64")
set(COREARCH "x64")
else()
message(FATAL ERROR "")
endif()

######################################
# EGLIB CHECKS
######################################

set (GNUC_PRETTY)
set (GNUC_UNUSED)
set (BREAKPOINT "G_STMT_START { raise (SIGTRAP); } G_STMT_END")
if (GCC)
set (GNUC_UNUSED "__attribute__((__unused__))")
set (GNUC_NORETURN "__attribute__((__noreturn__))")
if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86|x86_64")
set (BREAKPOINT "G_STMT_START { __asm__ (\"int \$03\"); } G_STMT_END")
endif ()
endif ()

if (IS_BIG_ENDIAN)
set (ORDER G_BIG_ENDIAN)
else ()
set (ORDER G_LITTLE_ENDIAN)
endif ()

if (WIN32)
# FIXME:
message (FATAL_ERROR "FIXME")
else ()
set(PATHSEP "/")
set(SEARCHSEP ":")
set(OS "UNIX")
set(PIDTYPE "int")
endif ()

# FIXME:
set(GSIZE_FORMAT "\"lu\"")

set(GSIZE "size_t")
set(GSSIZE "ptrdiff_t")

#
# END OF EGLIB CHECKS
#

TEST_BIG_ENDIAN (IS_BIG_ENDIAN)

# FIXME:
set(TARGET_SIZEOF_VOID_P "${SIZEOF_VOID_P}")
set(SIZEOF_REGISTER "${SIZEOF_VOID_P}")

if (IS_BIG_ENDIAN)
set(TARGET_BYTE_ORDER G_BIG_ENDIAN)
else()
set(TARGET_BYTE_ORDER G_LITTLE_ENDIAN)
endif()

set (RID "${RID_PREFIX}-${RID_SUFFIX}")

add_subdirectory (mono)

configure_file (cmake/config.h.in config.h)
configure_file (cmake/eglib-config.h.cmake.in mono/eglib/eglib-config.h)
configure_file (cmake/netcore-config.make.in netcore/config.make)
9 changes: 9 additions & 0 deletions src/mono/cmake/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Introduction

* This is an alternative CMAKE based build system for mono.
* The autoconf build system is still the official one.
* Only a subset of platforms/configurations etc. are supported.

# Usage

```cmake -DENABLE_NETCORE=1 -G Ninja .```
110 changes: 110 additions & 0 deletions src/mono/cmake/ac-to-cmake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env python3
import sys
import argparse
import subprocess

#
# Tool to extract configure.ac defines/checks from configure.ac for use with cmake.
# --autoheader -> generate a cmake style config.h.in
# --emit-cmake -> generate a starting cmake file
#

parser = argparse.ArgumentParser (prefix_chars = '-')
parser.add_argument('--autoheader', metavar='FILENAME', help='emit a config.h.in file')
parser.add_argument('--emit-cmake', metavar='FILENAME', help='emit a list of possible variables/configure options')
parser.add_argument('--filter-defines', metavar='FILENAME', help='list of defines to keep')
parser.add_argument('filename', help='path to configure.ac')
args = parser.parse_args ()

if args.filename == None:
parser.print_help ()
sys.exit (1)

if args.autoheader == None and args.emit_cmake == None:
sys.stderr.write ("At least one of --autoheader/--emit-cmake is required.")
sys.exit (1)

used_defines = None
if args.filter_defines != None:
used_defines = {}
with open (args.filter_defines) as f:
for line in f:
line = line.strip ()
used_defines [line] = 1

#'/usr/local/Cellar/autoconf/2.69/bin/autom4te' --language=autoconf --verbose --trace AC_CONFIG_HEADERS:'$$config_h ||= '"'"'$1'"'"';' --trace AH_OUTPUT:'A: $1 B $2 C;' --trace AC_DEFINE_TRACE_LITERAL:'$$symbol{'"'"'$1'"'"'} = 1;' configure.ac

# Generate a python script from configure.ac
proc = subprocess.Popen (["autom4te", "--language=autoconf", "--verbose", "--trace", "AH_OUTPUT:defs['$1'] = \"\"\"$2\"\"\"\n", "--trace", "AC_CHECK_HEADER:headers['$1'] = 1\n", "--trace", "AC_CHECK_HEADERS:headers['$1'] = 1\n", "--trace", "AC_CHECK_FUNCS:funcs['$1'] = 1\n", args.filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
outs, errs = proc.communicate ()
if proc.returncode != 0:
print (errs)
sys.exit (1)

with open ('tmp.py', 'w') as f:
f.write ('defs = {}\n')
f.write ('headers = {}\n')
f.write ('funcs = {}\n')
f.write (outs)

# Process it
import tmp

tmp.defs["VERSION"] = """/* Version number of package */
#undef VERSION"""

tmp.defs["HAVE_DLFCN_H"] = """/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H"""

if args.autoheader != None:
with open (args.autoheader, 'w') as f:
for define in tmp.defs.keys ():
if define == "MONO_CORLIB_VERSION" or define == "VERSION" or define == "MONO_ARCHITECTURE" or define == "DISABLED_FEATURES" or define.startswith ("SIZEOF_") or define.startswith ("TARGET_SIZEOF_") or define.startswith ("TARGET_BYTE_ORDER"):
f.write (tmp.defs [define].replace ("#undef " + define, "#define " + define + " @" + define + "@"))
elif False and define.startswith ("ENABLE_"):
f.write (tmp.defs [define].replace ('#undef', '#cmakedefine01'))
else:
f.write (tmp.defs [define].replace ('#undef ' + define, '#cmakedefine ' + define + ' 1'))
f.write ('\n\n')

emitted_defines = {}

if args.emit_cmake != None:
with open (args.emit_cmake, 'w') as f:
for value in tmp.headers.keys ():
for header in value.split (" "):
header = header.strip ()
if header == "":
continue
define = "HAVE_" + header.replace ("/", "_").replace (".", "_").replace ("-", "_").upper ()
emitted_defines [define] = 1
if used_defines != None and not define in used_defines:
continue
f.write ("check_include_file (\"" + header + "\" " + define + ")\n")

for value in tmp.funcs.keys ():
for func in value.split (" "):
func = func.strip ()
if func == "":
continue
define = "HAVE_" + func.replace ("/", "_").replace (".", "_").replace ("-", "_").upper ()
emitted_defines [define] = 1
if used_defines != None and not define in used_defines:
continue
f.write ("check_function_exists (\"" + func + "\" " + define + ")\n")
for pindex in range(2):
if pindex == 0:
f.write ("### Configure defines\n")
else:
f.write ("### User defines\n")
for define in tmp.defs.keys ():
if define in emitted_defines:
continue
if define.startswith ("HAVE_") and used_defines != None and not define in used_defines:
continue
val = tmp.defs [define]
is_def = "Define to 1 if" in val
if (pindex == 0 and is_def) or (pindex == 1 and not is_def):
f.write ("option (" + define + " \"" + tmp.defs [define].split (" */")[0].replace ("/*", "").replace ("\"", "").strip () + "\")\n")


29 changes: 29 additions & 0 deletions src/mono/cmake/collect-defines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
import sys
import re

defines={}
for filename in sys.argv[1:]:
with open (filename, 'r') as f:
for line in f:
line = line.strip ()
if '#ifdef' in line or '#ifndef' in line or '#elif' in line or '#if' in line:
line = line.replace ('defined ', 'defined').replace ('\t', ' ')
parts = line.split (' ')
if '#ifdef' in line or '#ifndef' in line:
defines [parts [1]] = 1
else:
for part in parts[1:]:
match = re.search ('defined\(([a-zA-Z0-9_]+)\)', part)
if match != None:
define = match.group (1)
defines [define] = 1
else:
match = re.search ('[a-zA-Z_][a-zA-Z0-9_]+', part)
if match != None:
define = match.group (0)
defines [define] = 1

for define in defines.keys ():
if define.startswith ("HAVE_"):
print (define)
Loading

0 comments on commit b10f41f

Please sign in to comment.