Skip to content

Commit ee467c8

Browse files
authored
setup basic logging for native and fix static libs (#98)
1 parent 082670c commit ee467c8

File tree

26 files changed

+225
-74
lines changed

26 files changed

+225
-74
lines changed

CMakeLists.txt

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
cmake_minimum_required(VERSION 3.1)
1+
cmake_minimum_required(VERSION 3.21)
22
project(aws-crt-kotlin C)
33
message(STATUS "CMake ${CMAKE_VERSION}")
4-
54
option(BUILD_DEPS "Builds aws common runtime dependencies as part of build. Turn off if you want to control your dependency chain." ON)
6-
option(BUILD_SHARED_LIBS "Build shared library for FFI: default: ON" ON)
5+
option(BUILD_SHARED_LIBS "Build shared library for FFI: default: OFF" OFF)
76

87
if (POLICY CMP0069)
98
cmake_policy(SET CMP0069 NEW) # Enable LTO/IPO if available in the compiler
@@ -21,12 +20,20 @@ if (UNIX AND NOT APPLE)
2120
set(FIND_LIBRARY_USE_LIB64_PATHS true)
2221
endif()
2322

23+
# Multi-config generators like Xcode, Visual Studio, and Ninja don't always respect
24+
# CMAKE_BUILD_TYPE. Set the available configuration to the build type.
25+
if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
26+
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
27+
message(STATUS "Setting CMAKE_CONFIGURATION_TYPES = ${CMAKE_CONFIGURATION_TYPES}")
28+
endif()
29+
2430
# This is required in order to append /lib/cmake to each element in CMAKE_PREFIX_PATH
2531
set(AWS_MODULE_DIR "/${CMAKE_INSTALL_LIBDIR}/cmake")
2632
string(REPLACE ";" "${AWS_MODULE_DIR};" AWS_MODULE_PATH "${CMAKE_PREFIX_PATH}${AWS_MODULE_DIR}")
2733
# Append that generated list to the module search path
2834
list(APPEND CMAKE_MODULE_PATH ${AWS_MODULE_PATH})
2935

36+
set(ADDITIONAL_DEPS "")
3037

3138
if (BUILD_DEPS)
3239
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/crt/aws-c-common/cmake")
@@ -60,6 +67,7 @@ if (BUILD_DEPS)
6067
set(DISABLE_GO ON)
6168
set(SEARCH_LIBCRYPTO OFF)
6269
set(BUILD_LIBSSL OFF)
70+
list(APPEND ADDITIONAL_DEPS crypto)
6371
add_subdirectory(crt/aws-lc)
6472
else()
6573
set(SEARCH_LIBCRYPTO ON)
@@ -74,6 +82,7 @@ if (BUILD_DEPS)
7482
endif()
7583
endif()
7684
add_subdirectory(crt/s2n)
85+
list(APPEND ADDITIONAL_DEPS s2n)
7786
endif()
7887
add_subdirectory(crt/aws-c-sdkutils)
7988
add_subdirectory(crt/aws-c-io)
@@ -87,9 +96,6 @@ else()
8796
set(IN_SOURCE_BUILD OFF)
8897
endif()
8998

90-
# Restore BUILD_SHARED_LIBS for this project
91-
set(BUILD_SHARED_LIBS ${SHARED_FFI_LIB})
92-
9399
include(AwsCFlags)
94100
include(AwsSharedLibSetup)
95101
include(AwsSanitizers)
@@ -103,7 +109,80 @@ aws_use_package(aws-c-http)
103109
aws_use_package(aws-c-auth)
104110
aws_use_package(aws-checksums)
105111

106-
# TODO - bundling static libraries into single static library composed of all the static libraries
107-
# to enable IPO/LTO. See also:
108-
# * https://cristianadam.eu/20190501/bundling-together-static-libraries-with-cmake/
109-
# * https://cmake.org/cmake/help/latest/module/CheckIPOSupported.html
112+
if (XCODE)
113+
# we only ever build for a single device/simulator and turning this on leaks into generator expressions like `$<TARGET_FILE:${tgt}>`
114+
# and breaks for ios/tvos/watchos builds
115+
set_property(GLOBAL PROPERTY XCODE_EMIT_EFFECTIVE_PLATFORM_NAME OFF)
116+
endif()
117+
118+
# Create a single static library that combines all the individual libs
119+
# We do this to work around issues with link order when including multiple
120+
# `staticLibraries` in the cinterop file.
121+
function(bundle_static_library name deps)
122+
set(tgt_full_name ${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX})
123+
124+
if(XCODE)
125+
find_program(lib_tool libtool)
126+
foreach(tgt IN LISTS deps)
127+
list(APPEND static_libs_full_names $<TARGET_FILE:${tgt}>)
128+
endforeach()
129+
130+
add_custom_command(
131+
COMMAND
132+
${lib_tool} -static -o ${tgt_full_name} ${static_libs_full_names}
133+
OUTPUT
134+
${tgt_full_name}
135+
COMMENT
136+
"Bundling ${name}"
137+
VERBATIM
138+
COMMAND_EXPAND_LISTS
139+
)
140+
141+
elseif (CMAKE_C_COMPILER_ID MATCHES "^(Clang|GNU)$")
142+
# archive tool needs to support -M flag
143+
file(WRITE ${CMAKE_BINARY_DIR}/${name}.ar.in "CREATE ${tgt_full_name}\n")
144+
145+
foreach(tgt IN LISTS deps)
146+
message("tgt=${tgt}")
147+
file(APPEND ${CMAKE_BINARY_DIR}/${name}.ar.in "ADDLIB $<TARGET_FILE:${tgt}>\n")
148+
endforeach()
149+
150+
file(APPEND ${CMAKE_BINARY_DIR}/${name}.ar.in "SAVE\n")
151+
file(APPEND ${CMAKE_BINARY_DIR}/${name}.ar.in "END\n")
152+
153+
file(
154+
GENERATE
155+
OUTPUT ${CMAKE_BINARY_DIR}/${name}.ar
156+
INPUT ${CMAKE_BINARY_DIR}/${name}.ar.in
157+
)
158+
159+
add_custom_command(
160+
COMMAND ${CMAKE_AR} -M < ${CMAKE_BINARY_DIR}/${name}.ar
161+
OUTPUT ${tgt_full_name}
162+
COMMENT "Bundling ${name}"
163+
VERBATIM
164+
)
165+
else()
166+
message(FATAL_ERROR "Unknown bundling!")
167+
endif()
168+
169+
add_custom_target(bundling_target ALL DEPENDS ${tgt_full_name})
170+
foreach(tgt IN LISTS deps)
171+
message("adding dependency on ${tgt}")
172+
add_dependencies(bundling_target ${tgt})
173+
endforeach()
174+
175+
add_library(${name} STATIC IMPORTED)
176+
set_target_properties(${name}
177+
PROPERTIES
178+
IMPORTED_LOCATION ${tgt_full_name}
179+
INTERFACE_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:${name},INTERFACE_INCLUDE_DIRECTORIES>)
180+
add_dependencies(${name} bundling_target)
181+
182+
install(FILES ${tgt_full_name} TYPE LIB)
183+
endfunction()
184+
185+
list(APPEND STATIC_LIBS ${DEP_AWS_LIBS} ${ADDITIONAL_DEPS})
186+
bundle_static_library(aws-crt-kotlin "${STATIC_LIBS}")
187+
188+
message("CMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}")

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ The `elasticurl` project contains an MPP (JVM and Native only) executable that p
8484
```
8585
# replace "PLATFORM" with the target platform you want to run (e.g. macosX64, linuxX64, etc)
8686
87-
./elasticurl/bin/PLATFORM/elasticurl.kexe [OPTIONS] URL
87+
./elasticurl/bin/PLATFORM/elasticurlDebugExecutable/elasticurl.kexe [OPTIONS] URL
8888
```
8989

9090

@@ -99,7 +99,7 @@ To enable memory tracing specify the environment variable `CRTDEBUG=trace=N` and
9999

100100
e.g.
101101
```
102-
CRTDEBUG=trace=2 ./elasticurl/bin/macosX64/elasticurl.kexe -v trace https://aws.amazon.com
102+
CRTDEBUG=trace=2 ./elasticurl/bin/macosX64/elasticurlDebugExecutable/elasticurl.kexe -v trace https://aws.amazon.com
103103
```
104104

105105

aws-crt-kotlin/build.gradle.kts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,6 @@ kotlin {
164164
dependsOn(cmakeInstallTask)
165165
}
166166
}
167-
168-
compilations["test"].compilerOptions.configure {
169-
// TODO - can we remove this if we are bundling the static libs
170-
freeCompilerArgs.addAll(listOf("-linker-options", "-L${libDir.absolutePath}"))
171-
}
172167
}
173168
}
174169

aws-crt-kotlin/native/interop/crt.def

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package = libcrt
22
headers = aws/common/allocator.h \
3+
aws/common/common.h \
34
aws/common/error.h \
45
aws/common/byte_buf.h \
56
aws/common/string.h \
@@ -21,21 +22,12 @@ headers = aws/common/allocator.h \
2122
aws/compression/compression.h
2223
headerFilter = aws/common/* aws/io/* aws/http/* aws/compression/*
2324

24-
linkerOpts = -laws-c-common -laws-c-cal -laws-c-io -laws-c-http -laws-c-compression
2525
linkerOpts.osx = -framework Security
2626
linkerOpts.ios = -framework Security
27-
linkerOpts.linux = -ls2n -lcrypto
2827

29-
staticLibraries = libaws-c-common.a \
30-
libaws-c-cal.a \
31-
libaws-c-io.a \
32-
libaws-c-compression.a \
33-
libaws-c-sdkutils.a \
34-
libaws-c-http.a \
35-
libaws-c-auth.a \
36-
libaws-checksums.a
37-
38-
staticLibraries.linux = libs2n.a libcrypto.a
28+
# included libs are linked automatically, adding linkerOpts like `-laws-c-common` causes
29+
# issues downstream as it will search for that library still.
30+
staticLibraries = libaws-crt-kotlin.a
3931

4032
---
4133

@@ -49,6 +41,24 @@ static void s_crt_kotlin_log(enum aws_log_level level, aws_log_subject_t subject
4941
static struct aws_allocator *s_crt_kotlin_allocator = NULL;
5042
int g_memtrace_level = 0;
5143

44+
#define AWS_CRT_KOTLIN_PACKAGE_ID 16
45+
46+
enum aws_kotlin_crt_log_subject {
47+
AWS_LS_KOTLIN_CRT_GENERAL = AWS_LOG_SUBJECT_BEGIN_RANGE(AWS_CRT_KOTLIN_PACKAGE_ID),
48+
AWS_LS_KOTLIN_CRT_LAST = AWS_LOG_SUBJECT_END_RANGE(AWS_CRT_KOTLIN_PACKAGE_ID)
49+
};
50+
51+
static struct aws_log_subject_info s_crt_log_subject_infos[] = {
52+
DEFINE_LOG_SUBJECT_INFO(
53+
AWS_LS_KOTLIN_CRT_GENERAL, "kotlin-crt-general", "Subject for aws-crt-kotlin logging that defies categorization"),
54+
};
55+
56+
static struct aws_log_subject_info_list s_crt_log_subject_list = {
57+
.subject_list = s_crt_log_subject_infos,
58+
.count = AWS_ARRAY_SIZE(s_crt_log_subject_infos),
59+
};
60+
61+
5262
static void s_crt_kotlin_init_allocator(int trace_level) {
5363
if (trace_level > 0) {
5464
g_memtrace_level = trace_level;
@@ -99,4 +109,4 @@ static void s_crt_kotlin_logger_cleanup(void) {
99109
aws_logger_set(NULL);
100110
aws_logger_clean_up(&s_crt_kotlin_logger);
101111
}
102-
}
112+
}

aws-crt-kotlin/native/src/aws/sdk/kotlin/crt/Allocator.kt

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,3 @@ internal class AwsAllocator : NativeFreeablePlacement, CValuesRef<aws_allocator>
2828

2929
override fun getPointer(scope: AutofreeScope): CPointer<aws_allocator> = allocator
3030
}
31-
32-
/**
33-
* Clean up CRT resources after K/N runtime has been released.
34-
*/
35-
@OptIn(ExperimentalForeignApi::class)
36-
internal fun cleanup() {
37-
aws_http_library_clean_up()
38-
aws_compression_library_clean_up()
39-
aws_io_library_clean_up()
40-
aws_common_library_clean_up()
41-
42-
s_crt_kotlin_clean_up()
43-
}

aws-crt-kotlin/native/src/aws/sdk/kotlin/crt/CRTNative.kt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55

66
package aws.sdk.kotlin.crt
77

8-
import kotlinx.cinterop.ExperimentalForeignApi
9-
import kotlinx.cinterop.convert
10-
import kotlinx.cinterop.staticCFunction
11-
import kotlinx.cinterop.toKString
8+
import kotlinx.cinterop.*
129
import kotlinx.coroutines.runBlocking
1310
import kotlinx.coroutines.sync.Mutex
1411
import kotlinx.coroutines.sync.withLock
@@ -39,6 +36,7 @@ public actual object CRT {
3936
aws_http_library_init(Allocator.Default)
4037

4138
Logging.initialize(config)
39+
aws_register_log_subject_info_list(s_crt_log_subject_list.ptr)
4240
atexit(staticCFunction(::cleanup))
4341

4442
initialized = true
@@ -102,3 +100,16 @@ public actual object CRT {
102100
0
103101
}
104102
}
103+
104+
/**
105+
* Clean up CRT resources after K/N runtime has been released.
106+
*/
107+
private fun cleanup() {
108+
aws_unregister_log_subject_info_list(s_crt_log_subject_list.ptr)
109+
aws_http_library_clean_up()
110+
aws_compression_library_clean_up()
111+
aws_io_library_clean_up()
112+
aws_common_library_clean_up()
113+
114+
s_crt_kotlin_clean_up()
115+
}

aws-crt-kotlin/native/src/aws/sdk/kotlin/crt/Logging.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,7 @@ internal object Logging {
6868
}
6969
}
7070
}
71+
72+
internal inline fun log(level: LogLevel, message: String, subject: aws_log_subject_t = AWS_LS_KOTLIN_CRT_GENERAL) {
73+
s_crt_kotlin_log(level.value.convert(), subject, message)
74+
}

aws-crt-kotlin/native/src/aws/sdk/kotlin/crt/http/HttpClientConnectionNative.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ private fun onResponseHeaders(
154154
try {
155155
ctx.handler.onResponseHeaders(stream, stream.responseStatusCode, blockType.value.toInt(), headers)
156156
} catch (ex: Exception) {
157+
log(LogLevel.Error, "onResponseHeaders: $ex")
157158
return aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE.toInt())
158159
}
159160
return AWS_OP_SUCCESS
@@ -169,6 +170,7 @@ private fun onResponseHeaderBlockDone(
169170
try {
170171
ctx.handler.onResponseHeadersDone(stream, blockType.value.toInt())
171172
} catch (ex: Exception) {
173+
log(LogLevel.Error, "onResponseHeaderBlockDone: $ex")
172174
return aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE.toInt())
173175
}
174176

@@ -194,7 +196,7 @@ private fun onIncomingBody(
194196
aws_http_stream_update_window(nativeStream, windowIncrement.convert())
195197
}
196198
} catch (ex: Exception) {
197-
// FIXME - we need our own logging block so we can log exceptions and errors from FFI layer
199+
log(LogLevel.Error, "onIncomingBody: $ex")
198200
return aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE.toInt())
199201
}
200202

@@ -212,6 +214,7 @@ private fun onStreamComplete(
212214
try {
213215
ctx.handler.onResponseComplete(stream, errorCode)
214216
} catch (ex: Exception) {
217+
log(LogLevel.Error, "onStreamComplete: $ex")
215218
// close connection if callback throws an exception
216219
aws_http_connection_close(aws_http_stream_get_connection(nativeStream))
217220
} finally {

aws-crt-kotlin/native/src/aws/sdk/kotlin/crt/http/RequestBodyStream.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
package aws.sdk.kotlin.crt.http
66

77
import aws.sdk.kotlin.crt.Allocator
8+
import aws.sdk.kotlin.crt.LogLevel
89
import aws.sdk.kotlin.crt.io.MutableBuffer
10+
import aws.sdk.kotlin.crt.log
911
import kotlinx.cinterop.*
1012
import libcrt.*
1113

@@ -23,6 +25,7 @@ private fun streamSeek(
2325
result = AWS_OP_ERR
2426
}
2527
} catch (ex: Exception) {
28+
log(LogLevel.Error, "streamSeek: $ex")
2629
return aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE.toInt())
2730
}
2831

@@ -45,6 +48,7 @@ private fun streamRead(
4548
val buffer = MutableBuffer(dest)
4649
handler.khandler.sendRequestBody(buffer)
4750
} catch (ex: Exception) {
51+
log(LogLevel.Error, "streamRead: $ex")
4852
return aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE.toInt())
4953
}
5054

@@ -80,6 +84,7 @@ private fun streamRelease(
8084
if (stream == null) return
8185
val refCnt = aws_ref_count_release(stream.pointed.ref_count.ptr)
8286
if (refCnt.toInt() == 0) {
87+
log(LogLevel.Trace, "releasing RequestBodyStream")
8388
val stableRef = stream.pointed.impl?.asStableRef<RequestBodyStream>() ?: return
8489
stableRef.dispose()
8590
Allocator.Default.free(stream)

aws-crt-kotlin/native/src/aws/sdk/kotlin/crt/util/StringUtils.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ public fun String.toAwsString(): CPointer<aws_string> =
4949
*/
5050
public fun Pinned<ByteArray>.asAwsByteCursor(): CValue<aws_byte_cursor> {
5151
val arr = get()
52-
val addr = addressOf(0)
52+
val addr = if (arr.isNotEmpty()) addressOf(0) else null
5353
return cValue<aws_byte_cursor> {
5454
len = arr.size.convert()
55-
ptr = addr.reinterpret()
55+
ptr = addr?.reinterpret()
5656
}
5757
}
5858

0 commit comments

Comments
 (0)