-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
511 lines (453 loc) · 17.1 KB
/
CMakeLists.txt
File metadata and controls
511 lines (453 loc) · 17.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
cmake_minimum_required(VERSION 3.16)
project(cchem VERSION 1.0.0 LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
# Detect architecture
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64|ARM64")
set(CCHEM_ARCH_ARM64 TRUE)
message(STATUS "Architecture: ARM64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
set(CCHEM_ARCH_X64 TRUE)
message(STATUS "Architecture: x86_64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i[3-6]86|x86")
set(CCHEM_ARCH_X86 TRUE)
message(STATUS "Architecture: x86")
else()
message(STATUS "Architecture: ${CMAKE_SYSTEM_PROCESSOR} (generic)")
endif()
# Platform-specific definitions
if(WIN32)
# Windows: Enable POSIX-like functions and large file support
add_compile_definitions(_CRT_SECURE_NO_WARNINGS _USE_MATH_DEFINES)
if(MSVC)
add_compile_definitions(_CRT_NONSTDC_NO_DEPRECATE)
endif()
elseif(APPLE)
# macOS: Darwin provides POSIX by default
add_compile_definitions(_DARWIN_C_SOURCE)
else()
# Linux/BSD: Enable GNU extensions for POSIX functions
add_compile_definitions(_GNU_SOURCE)
endif()
# Enable Link Time Optimization (LTO) for Release builds
include(CheckIPOSupported)
check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_OUTPUT)
if(LTO_SUPPORTED AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
message(STATUS "LTO enabled")
else()
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "LTO not supported: ${LTO_OUTPUT}")
endif()
endif()
# Option to enable sanitizers (Debug only)
option(ENABLE_SANITIZERS "Enable AddressSanitizer and UBSan (Debug only)" OFF)
# Option to build for native CPU (disable for portable binaries)
option(ENABLE_NATIVE_ARCH "Optimize for native CPU architecture" ON)
# Compiler-specific flags
if(MSVC)
# Microsoft Visual C++
message(STATUS "Compiler: MSVC ${MSVC_VERSION}")
# Enable C11 atomics support
add_compile_options(/std:c11)
# Base warnings (W4 is high warning level)
add_compile_options(/W4)
# Disable specific noisy warnings
add_compile_options(/wd4100) # unreferenced formal parameter
add_compile_options(/wd4244) # conversion, possible loss of data
add_compile_options(/wd4267) # size_t to int conversion
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(/Od /Zi /RTC1)
else()
# Release optimizations
add_compile_options(
/O2 # Maximize speed
/Oi # Enable intrinsic functions
/Ot # Favor fast code
/GL # Whole program optimization
/fp:fast # Fast floating point
/GS- # Disable buffer security check for speed
)
add_link_options(/LTCG) # Link-time code generation
# Architecture-specific optimizations
if(CCHEM_ARCH_X64 AND ENABLE_NATIVE_ARCH)
add_compile_options(/arch:AVX2)
elseif(CCHEM_ARCH_X86 AND ENABLE_NATIVE_ARCH)
add_compile_options(/arch:SSE2)
endif()
endif()
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
# GCC, Clang, AppleClang
message(STATUS "Compiler: ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}")
# Base warnings
add_compile_options(-Wall -Wextra -Wpedantic)
# Additional useful warnings
add_compile_options(
-Wformat=2
-Wno-unused-parameter
-Wno-sign-compare
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
# Debug build
add_compile_options(-g -O0)
if(ENABLE_SANITIZERS)
message(STATUS "Sanitizers enabled (ASan + UBSan)")
add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer)
add_link_options(-fsanitize=address,undefined)
endif()
else()
# Release/default build: aggressive optimizations
add_compile_options(
-O3 # Aggressive optimization
-ffast-math # Fast floating point (safe for descriptors)
-fno-strict-aliasing # Allow type punning patterns
-funroll-loops # Unroll small loops
-ftree-vectorize # Enable vectorization
)
# Architecture-specific optimizations
if(ENABLE_NATIVE_ARCH)
# Native architecture - best performance on build machine
add_compile_options(-march=native -mtune=native)
else()
# Portable binaries with reasonable baseline
if(CCHEM_ARCH_ARM64)
if(APPLE)
# Apple Silicon baseline (M1+)
add_compile_options(-mcpu=apple-m1)
else()
# Generic ARMv8.2-A with common extensions
add_compile_options(-march=armv8.2-a+fp16+dotprod)
endif()
elseif(CCHEM_ARCH_X64)
# x86_64 baseline: SSE4.2 is universal on modern CPUs
add_compile_options(-march=x86-64-v2)
elseif(CCHEM_ARCH_X86)
add_compile_options(-march=i686 -msse2)
endif()
endif()
# Clang-specific optimizations
if(CMAKE_C_COMPILER_ID MATCHES "Clang|AppleClang")
add_compile_options(-fvectorize -fslp-vectorize)
endif()
# GCC-specific optimizations
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
add_compile_options(-fipa-pta -fgraphite-identity)
endif()
endif()
# Platform-specific linker flags
if(APPLE)
# Suppress Homebrew LLVM libunwind reexport warnings
add_link_options(-Wl,-w)
elseif(UNIX AND NOT APPLE)
# Linux: Enable relro and now for security, disable for performance if needed
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
add_link_options(-Wl,-O1 -Wl,--as-needed)
endif()
endif()
elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel" OR CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM")
# Intel compilers (icc/icx)
message(STATUS "Compiler: Intel ${CMAKE_C_COMPILER_VERSION}")
add_compile_options(-Wall)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-g -O0)
else()
add_compile_options(
-O3
-xHost # Optimize for host CPU
-ipo # Interprocedural optimization
-fp-model=fast
-qopt-zmm-usage=high
)
endif()
endif()
# Print build configuration summary
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Native arch optimization: ${ENABLE_NATIVE_ARCH}")
# Find required libraries
if(WIN32)
# On Windows with vcpkg, use pthreads-win32
find_package(PThreads4W CONFIG)
if(PThreads4W_FOUND)
set(THREADS_LIBRARIES PThreads4W::PThreads4W)
message(STATUS "Found pthreads-win32 (PThreads4W)")
else()
# Fallback to Threads package
find_package(Threads REQUIRED)
set(THREADS_LIBRARIES Threads::Threads)
endif()
# On Windows, we need getopt from vcpkg
find_package(unofficial-getopt-win32 CONFIG)
if(unofficial-getopt-win32_FOUND)
set(GETOPT_LIBRARIES unofficial::getopt-win32::getopt)
message(STATUS "Found getopt-win32")
else()
# Try alternative package name
find_library(GETOPT_LIBRARY NAMES getopt)
if(GETOPT_LIBRARY)
set(GETOPT_LIBRARIES ${GETOPT_LIBRARY})
message(STATUS "Found getopt: ${GETOPT_LIBRARY}")
else()
message(WARNING "getopt not found - CLI may not work on Windows")
set(GETOPT_LIBRARIES "")
endif()
endif()
else()
find_package(Threads REQUIRED)
set(THREADS_LIBRARIES Threads::Threads)
set(GETOPT_LIBRARIES "") # getopt is built-in on Unix
endif()
# Find Cairo - use different methods per platform
option(WITH_CAIRO "Build with Cairo support for 2D rendering" ON)
if(WITH_CAIRO)
if(WIN32)
# On Windows with vcpkg, use find_package directly
find_package(unofficial-cairo CONFIG)
if(unofficial-cairo_FOUND)
set(CAIRO_FOUND TRUE)
set(CAIRO_LIBRARIES unofficial::cairo::cairo)
set(CAIRO_INCLUDE_DIRS "") # vcpkg handles this via target
else()
# Fallback: try cairo directly
find_package(Cairo CONFIG)
if(Cairo_FOUND)
set(CAIRO_FOUND TRUE)
set(CAIRO_LIBRARIES Cairo::Cairo)
set(CAIRO_INCLUDE_DIRS "")
endif()
endif()
else()
# On Unix, use pkg-config
find_package(PkgConfig REQUIRED)
pkg_check_modules(CAIRO REQUIRED cairo)
endif()
if(NOT CAIRO_FOUND)
message(WARNING "Cairo not found - 2D rendering will be disabled")
set(WITH_CAIRO OFF)
endif()
endif()
# Find JPEG - only needed when Cairo is enabled (for image output)
if(WITH_CAIRO)
find_package(JPEG REQUIRED)
set(HAVE_JPEG TRUE)
else()
set(HAVE_JPEG FALSE)
endif()
# Fetch and build carquet library for Parquet support
include(FetchContent)
FetchContent_Declare(
carquet
GIT_REPOSITORY https://github.com/Vitruves/carquet.git
GIT_TAG main
GIT_SHALLOW TRUE
)
# Configure carquet build options (disable tests/examples/benchmarks)
set(CARQUET_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(CARQUET_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(CARQUET_BUILD_BENCHMARKS OFF CACHE BOOL "" FORCE)
message(STATUS "Fetching carquet from GitHub...")
FetchContent_MakeAvailable(carquet)
set(HAVE_CARQUET TRUE)
message(STATUS "carquet available for Parquet support")
# Include directories
include_directories(${CMAKE_SOURCE_DIR}/include)
if(HAVE_JPEG)
include_directories(${JPEG_INCLUDE_DIR})
endif()
if(WITH_CAIRO AND CAIRO_INCLUDE_DIRS)
include_directories(${CAIRO_INCLUDE_DIRS})
endif()
if(WITH_CAIRO AND CAIRO_LIBRARY_DIRS)
link_directories(${CAIRO_LIBRARY_DIRS})
endif()
include_directories(${carquet_SOURCE_DIR}/include)
# Library sources
set(CCHEM_SOURCES
src/canonicalizer/atom.c
src/canonicalizer/bond.c
src/canonicalizer/molecule.c
src/canonicalizer/lexer.c
src/canonicalizer/parser.c
src/canonicalizer/invariant.c
src/canonicalizer/canon.c
src/canonicalizer/smiles_writer.c
src/canonicalizer/ring_finder.c
src/canonicalizer/stereo.c
src/canonicalizer/sanitize.c
src/utils/memory.c
src/utils/threading.c
src/utils/csv.c
src/utils/progress.c
$<$<BOOL:${HAVE_CARQUET}>:src/utils/parquet.c>
src/splitter/splitter.c
src/descriptors/registry.c
src/descriptors/counts.c
src/descriptors/logp.c
src/descriptors/ratios.c
src/descriptors/electronic.c
src/descriptors/steric.c
src/descriptors/energetics.c
src/descriptors/bitstring.c
src/descriptors/acidbase.c
src/descriptors/solubility.c
src/descriptors/topology.c
src/descriptors/fractional.c
src/descriptors/hash.c
src/descriptors/graph.c
src/descriptors/autocorrelations.c
src/descriptors/logd74.c
src/descriptors/functional.c
src/descriptors/pharmacophore.c
src/descriptors/mqn.c
src/descriptors/estate.c
src/descriptors/vsa.c
src/descriptors/chi.c
src/descriptors/atompairs.c
src/descriptors/bcut.c
src/descriptors/zagreb.c
src/descriptors/infocontent.c
src/descriptors/walkcounts.c
src/descriptors/estate_sums.c
src/descriptors/eta.c
src/descriptors/ringcomplexity.c
src/descriptors/cpsa.c
src/descriptors/bcut_ext.c
src/descriptors/moments.c
src/descriptors/aromatic.c
src/descriptors/atompairs_ext.c
src/descriptors/framework.c
src/descriptors/constitutional.c
# Depictor sources - only include when Cairo is available
$<$<BOOL:${WITH_CAIRO}>:src/depictor/types.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/colors.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/coords2d.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/layout_utils.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/ring_systems.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/ring_templates.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/ring_placement.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/chain_placement.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/collision.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/force_directed.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/coords3d.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/render.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/depictor.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/mmff94_typing.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/mmff94_charges.c>
$<$<BOOL:${WITH_CAIRO}>:src/depictor/mmff94_energy.c>
)
# Create static library
add_library(cchem_lib STATIC ${CCHEM_SOURCES})
# Use PUBLIC for THREADS_LIBRARIES so pthread include directories propagate to consumers
target_link_libraries(cchem_lib PUBLIC ${THREADS_LIBRARIES})
if(HAVE_JPEG)
target_link_libraries(cchem_lib PRIVATE ${JPEG_LIBRARIES})
endif()
if(WITH_CAIRO)
target_link_libraries(cchem_lib PRIVATE ${CAIRO_LIBRARIES})
endif()
if(NOT WIN32)
target_link_libraries(cchem_lib PRIVATE m)
endif()
if(CAIRO_LIBRARY_DIRS)
target_link_directories(cchem_lib PRIVATE ${CAIRO_LIBRARY_DIRS})
endif()
if(HAVE_CARQUET)
target_link_libraries(cchem_lib PRIVATE carquet)
target_compile_definitions(cchem_lib PRIVATE HAVE_PARQUET=1)
endif()
# Helper variable for test libraries (m on Unix, nothing on Windows)
if(WIN32)
set(MATH_LIBRARY "")
else()
set(MATH_LIBRARY m)
endif()
# Main executable
add_executable(cchem
src/main.c
src/commands/cmd_canonicalize.c
src/commands/cmd_validate.c
src/commands/cmd_compute.c
$<$<BOOL:${WITH_CAIRO}>:src/commands/cmd_depict.c>
src/commands/cmd_split.c
)
target_link_libraries(cchem PRIVATE cchem_lib ${THREADS_LIBRARIES})
if(HAVE_JPEG)
target_link_libraries(cchem PRIVATE ${JPEG_LIBRARIES})
endif()
if(WITH_CAIRO)
target_link_libraries(cchem PRIVATE ${CAIRO_LIBRARIES})
target_compile_definitions(cchem PRIVATE HAVE_CAIRO=1)
target_compile_definitions(cchem_lib PRIVATE HAVE_CAIRO=1)
endif()
if(NOT WIN32)
target_link_libraries(cchem PRIVATE m)
endif()
if(WIN32 AND GETOPT_LIBRARIES)
target_link_libraries(cchem PRIVATE ${GETOPT_LIBRARIES})
endif()
if(HAVE_CARQUET)
target_compile_definitions(cchem PRIVATE HAVE_PARQUET=1)
target_link_libraries(cchem PRIVATE carquet)
endif()
# Tests
enable_testing()
add_executable(test_lexer tests/test_lexer.c)
target_link_libraries(test_lexer PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_lexer COMMAND test_lexer)
add_executable(test_parser tests/test_parser.c)
target_link_libraries(test_parser PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_parser COMMAND test_parser)
add_executable(test_molecule tests/test_molecule.c)
target_link_libraries(test_molecule PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_molecule COMMAND test_molecule)
add_executable(test_canon tests/test_canon.c)
target_link_libraries(test_canon PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_canon COMMAND test_canon)
add_executable(test_integration tests/test_integration.c)
target_link_libraries(test_integration PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_integration COMMAND test_integration)
add_executable(test_stereo tests/test_stereo.c)
target_link_libraries(test_stereo PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_stereo COMMAND test_stereo)
add_executable(test_debug tests/test_debug.c)
target_link_libraries(test_debug PRIVATE cchem_lib ${MATH_LIBRARY})
add_executable(test_descriptors tests/test_descriptors.c)
target_link_libraries(test_descriptors PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_descriptors COMMAND test_descriptors)
add_executable(test_descriptors_extended tests/test_descriptors_extended.c)
target_link_libraries(test_descriptors_extended PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_descriptors_extended COMMAND test_descriptors_extended)
if(WITH_CAIRO)
add_executable(test_mmff94 tests/test_mmff94.c)
target_link_libraries(test_mmff94 PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_mmff94 COMMAND test_mmff94)
endif()
add_executable(test_sanitize tests/test_sanitize.c)
target_link_libraries(test_sanitize PRIVATE cchem_lib ${MATH_LIBRARY})
add_test(NAME test_sanitize COMMAND test_sanitize)
# LogD 7.4 development test
#add_executable(logd74_test temp/logd74.c)
#target_link_libraries(logd74_test PRIVATE cchem_lib m)
# LogD 7.4 verification test
#add_executable(verify_logd74 temp/verify_logd74.c)
#target_link_libraries(verify_logd74 PRIVATE cchem_lib m)
# LogP neural network training
#add_executable(logp_nn temp/logp_nn.c)
#target_link_libraries(logp_nn PRIVATE cchem_lib m)
# LogP verification test
#add_executable(verify_logp temp/verify_logp.c)
#target_link_libraries(verify_logp PRIVATE cchem_lib m)
# Benchmarks (optional)
option(BUILD_BENCHMARKS "Build performance benchmarks" OFF)
option(WITH_RDKIT "Build benchmarks with RDKit support" OFF)
option(WITH_OPENBABEL "Build benchmarks with OpenBabel support" OFF)
if(BUILD_BENCHMARKS)
# Enable C++ for the benchmark
enable_language(CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(benchmarks)
endif()
# Install
install(TARGETS cchem RUNTIME DESTINATION bin)
install(DIRECTORY include/cchem DESTINATION include)