Repository navigation
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
2867 lines (2710 loc) · 151 KB
/
Copy pathCMakeLists.txt
File metadata and controls
2867 lines (2710 loc) · 151 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
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
cmake_minimum_required(VERSION 3.16)
project(ECCE CXX C Fortran)
# ------------------------------------------------------------------------
# This replaces the wx-independent portion of the old build_ecce / recursive
# Makefile system (build/build_ecce, build/make/Makefile.*). It targets the
# distro-packaged versions of wxWidgets/Xerces-C/Mesa rather than building
# vendored copies from build/3rdparty-dists/ as the old system did.
#
# Status: covers src/util, src/tdat, src/dsm, src/viz, src/comm, src/inv
# (minus src/inv/wxinv, which needs wxWidgets and hasn't been ported to
# wx 3.2 yet). src/apps, src/wxgui, src/wxviz are not yet included here -
# they need the wx 2.8->3.2 port first. See
# claude/ecce-modernization-status.md in the project docs for full status.
# ------------------------------------------------------------------------
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Every .c (not .C) file in this tree (under src/inv/dbnodes,
# src/inv/flclient, src/inv/image, src/wxgui/wxplotctrl)
# is vendored ~1990s third-party C, riddled with K&R-style empty-parens
# forward declarations (e.g. `char *foo();`, later defined and called with
# real arguments) -- valid, unambiguous C when empty parens
# mean "unspecified arguments" (K&R/C89 through GNU's own default
# extensions), a hard error under newer C standard defaults where empty
# parens instead mean "takes no arguments". Confirmed via real Fedora CI
# build failures (newer default GCC) not reproducible on Debian/Ubuntu
# (older default GCC) -- pin C compilation tree-wide to gnu17 rather than
# rewriting decades-old third-party prototypes file by file as each one
# surfaces on whichever platform's default happens to be newest this
# month. Only affects .c compilation -- CMAKE_CXX_STANDARD above is
# separate and unaffected.
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
# ------------------------------------------------------------------------
# Road to 9.0, step 1: split the single monolithic package into
# ecce-client (GUI apps, input generators/parsers, codereg dialogs, the
# job-side scripts the Launcher copies to compute hosts, the per-session
# gateway scripts, ecce-remote-setup) and ecce-server (the per-user
# or central WebDAV data server and its content, its mosquitto
# dependency). Every install() rule below carries a
# COMPONENT tag either way -- that costs nothing when this is OFF, since
# plain `cpack`/`cpack -G DEB` ignores COMPONENT entirely and produces
# one monolithic package exactly as before (CPACK_DEB_COMPONENT_INSTALL
# defaults OFF). Turning this ON is what makes CPack actually split them.
# ON from 9.0 (ecce-client and ecce-server); 8.x release branches are monolithic.
option(ECCE_SPLIT_PACKAGES "Package ecce-client and ecce-server as separate .deb/.rpm files instead of one monolithic package" ON)
add_compile_options(-Wall -Wno-deprecated -Wno-sign-compare -Wno-non-virtual-dtor)
find_package(XercesC REQUIRED)
find_package(OpenGL REQUIRED)
find_package(wxWidgets 3.2 REQUIRED COMPONENTS core base gl aui net html)
include(${wxWidgets_USE_FILE})
find_package(PkgConfig)
# X11/GLX/EGL are the viewer's window-system layer (GlPlatform) on Linux and
# the BSDs only; macOS and Windows use wx's own GL canvas (#232).
if(UNIX AND NOT APPLE)
set(_ecce_gl_x11_default ON)
else()
set(_ecce_gl_x11_default OFF)
endif()
option(ECCE_GL_X11 "Viewer GL through X11/GLX/EGL (GlPlatform); OFF on macOS/Windows" ${_ecce_gl_x11_default})
if(ECCE_GL_X11)
find_package(X11 REQUIRED)
set(ECCE_X11_LIBS X11::X11)
add_compile_definitions(ECCE_GL_X11=1)
else()
set(ECCE_X11_LIBS "")
add_compile_definitions(ECCE_GL_X11=0)
endif()
# ESP grid evaluation runs on worker threads (ComputeMoCmd).
find_package(Threads REQUIRED)
link_libraries(Threads::Threads)
if(ECCE_GL_X11 AND NOT X11_Xt_FOUND)
message(FATAL_ERROR "libXt (X Toolkit Intrinsics) headers not found - included by include/inv/SoWx/SoWxViewer.H")
endif()
# Old build used "-I/usr/include/freetype2/freetype" as a baseline include
# dir everywhere, because most FreeType headers this codebase includes
# unqualified (e.g. <ftoutln.h>) live one level below the freetype2 package's
# normal include root. Keep that same include shape rather than switching to
# find_package(Freetype), to stay behavior-identical to the verified Make
# build. (One file, flclient/flfreetype.c, also needs <ft2build.h> itself,
# which lives at the freetype2 root one level up - handled separately below,
# on just the ecceinv target, matching the old per-directory Makefile.)
# Homebrew's freetype2 package lands at /opt/homebrew (Apple Silicon) or
# /usr/local (Intel Mac) instead of /usr -- neither hardcoded Linux path
# above exists there at all, and find_path() silently returns
# "...-NOTFOUND" rather than erroring, which only surfaces later as a
# baffling "Found relative path while evaluating include directories"
# CMake generate-step error. Confirmed via a real macOS CI run.
# PATH_SUFFIXES covers prefixes such as MSYS2's /ucrt64 (#133).
find_path(FREETYPE_UNQUALIFIED_INCLUDE_DIR ftoutln.h
PATH_SUFFIXES freetype2/freetype
PATHS /usr/include/freetype2/freetype /usr/include/freetype
/opt/homebrew/include/freetype2/freetype
/usr/local/include/freetype2/freetype)
if(NOT FREETYPE_UNQUALIFIED_INCLUDE_DIR)
message(FATAL_ERROR "FreeType's freetype/ include subdir (ftoutln.h) not found -- searched the usual Linux and Homebrew locations")
endif()
include_directories(
${CMAKE_SOURCE_DIR}/include
${FREETYPE_UNQUALIFIED_INCLUDE_DIR}
)
# #166: build against the system Coin3D instead of the
# vendored Inventor core in src/inv. <inv/X/Y.H> includes are forwarded to
# <Inventor/X/Y.h> by a generated overlay that is searched before include/.
option(ECCE_USE_COIN "Build against the system Coin3D (default). OFF builds the vendored Inventor core in src/inv, kept as a fallback for one release (#166)" ON)
if(ECCE_USE_COIN)
file(GLOB _coin_scan LIST_DIRECTORIES true ${CMAKE_SOURCE_DIR}/src/*)
list(FILTER _coin_scan EXCLUDE REGEX "/src/inv$")
file(GLOB _coin_scan_inc LIST_DIRECTORIES true ${CMAKE_SOURCE_DIR}/include/*)
list(FILTER _coin_scan_inc EXCLUDE REGEX "/include/inv$")
list(APPEND _coin_scan ${_coin_scan_inc})
# Coin 4.0.10 as packaged by EPEL/Fedora installs under include/Coin4, so
# the directory holding Inventor/ is found, not assumed to be /usr/include.
find_path(COIN_INCLUDE_DIR Inventor/SbString.h PATH_SUFFIXES Coin4 Coin3 Coin REQUIRED)
execute_process(COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/coin/gen_shim.py
${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}/coin-shim ${COIN_INCLUDE_DIR} ${_coin_scan}
RESULT_VARIABLE _shim_rc)
if(NOT _shim_rc EQUAL 0)
message(FATAL_ERROR "gen_shim.py failed")
endif()
include_directories(BEFORE ${CMAKE_BINARY_DIR}/coin-shim)
if(NOT COIN_INCLUDE_DIR STREQUAL "/usr/include")
include_directories(${COIN_INCLUDE_DIR})
endif()
add_compile_definitions(OIV_COIN)
find_library(COIN_LIBRARY Coin REQUIRED)
endif()
if(WIN32)
# MSYS2's Coin is a DLL; moiv is a static library of ours. GL/gl.h pulls in
# <windows.h>, whose full form drags in rpcndr.h's `byte`, ambiguous with
# std::byte under `using namespace std`; and its min/max macros break
# std::min/std::max. _POSIX_THREAD_SAFE_FUNCTIONS declares gmtime_r and
# localtime_r (#133).
add_compile_definitions(COIN_DLL CHEMKIT_NOT_DLL WIN32_LEAN_AND_MEAN NOMINMAX
_POSIX_THREAD_SAFE_FUNCTIONS=200112L)
# PosixCompat.H in every C++ file: it supplies the POSIX calls and strips
# the windows.h macros (ERROR, OPAQUE, ...) that wx pulls in first.
# win32compat/ stands in for the <sys/wait.h>-style headers MinGW lacks.
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:SHELL:-include ${CMAKE_SOURCE_DIR}/include/util/PosixCompat.H>")
include_directories(${CMAKE_SOURCE_DIR}/include/win32compat)
endif()
if(APPLE)
# ~90 files across the tree spell OpenGL headers the Linux/X11 way
# ("GL/gl.h", "GL/glu.h") -- Apple's own OpenGL framework headers live
# under "OpenGL/" instead. A forwarding shim here (packaging/macos-
# compat/GL/{gl,glu}.h) avoids editing every one of those call sites;
# placed last so it never shadows a real GL/ dir if one somehow exists.
include_directories(AFTER ${CMAKE_SOURCE_DIR}/packaging/macos-compat)
endif()
set(ECCE_VERSION_RAW "")
if(EXISTS ${CMAKE_SOURCE_DIR}/data/client/config/Version)
file(STRINGS ${CMAKE_SOURCE_DIR}/data/client/config/Version ECCE_VERSION_RAW LIMIT_COUNT 1)
# file(STRINGS ...) is a configure-time read, not a build dependency --
# CMake won't notice this file changed on a later `cmake --build` alone.
# Registering it here makes an edit to the Version file trigger an
# automatic reconfigure the next time anything is built.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
${CMAKE_SOURCE_DIR}/data/client/config/Version)
endif()
# ------------------------------------------------------------------------
# Helper: define a static library from an explicit list of source
# directories (matches the old build's grouping of multiple src/<mod>/<sub>
# directories into one libecceXXX.a - see per-directory LIBRARY= lines in
# the old Makefiles for the mapping this replicates).
# ------------------------------------------------------------------------
function(ecce_library name)
set(_srcs)
foreach(dir ${ARGN})
file(GLOB _dir_srcs CONFIGURE_DEPENDS
${CMAKE_SOURCE_DIR}/${dir}/*.C
${CMAKE_SOURCE_DIR}/${dir}/*.c)
list(APPEND _srcs ${_dir_srcs})
endforeach()
add_library(${name} STATIC ${_srcs})
target_include_directories(${name} PRIVATE ${XercesC_INCLUDE_DIRS})
if(WIN32)
# The libraries reference each other in cycles; GNU ld needs them repeated.
set_target_properties(${name} PROPERTIES LINK_INTERFACE_MULTIPLICITY 3)
endif()
endfunction()
# --- src/util -> libecceutil.a ---
ecce_library(ecceutil
src/util/chemutil
src/util/command
src/util/events
src/util/exceptions
src/util/genutil
src/util/jms
src/util/units
)
target_compile_definitions(ecceutil PRIVATE ECCE_VERSION=\"${ECCE_VERSION_RAW}\")
# Messaging (src/util/jms) is MQTT 5 on libmosquitto.
pkg_check_modules(MOSQUITTO REQUIRED IMPORTED_TARGET libmosquitto)
target_link_libraries(ecceutil PUBLIC PkgConfig::MOSQUITTO)
if(WIN32)
# POSIX regex (libtre) and Winsock, which libssh's callers use directly.
target_link_libraries(ecceutil PUBLIC regex ws2_32)
endif()
# ------------------------------------------------------------------------
# Where an installed ECCE lives, and where its ecce-<app> wrappers go.
#
# Both default to what the .deb ships (/opt/ecce and /usr/bin), so packaging
# is unaffected. They are cache variables so that a developer can install to
# somewhere writable and skip sudo entirely:
#
# cmake -B build-user -GNinja \
# -DCMAKE_INSTALL_PREFIX=$HOME/.local/ecce \
# -DECCE_HOME_DIR=$HOME/.local/ecce \
# -DECCE_WRAPPER_DESTINATION=$HOME/.local/bin
# cmake --build build-user --target install
#
# That matters for more than convenience: tests/apps can only exercise an
# INSTALLED build, so without this every test of a C++ change needs root.
# ------------------------------------------------------------------------
set(ECCE_HOME_DIR "/opt/ecce" CACHE PATH
"Directory an installed ECCE runs from; wrappers export it as ECCE_HOME")
set(ECCE_WRAPPER_DESTINATION "/usr/bin" CACHE PATH
"Where the ecce-<app> wrapper scripts are installed")
# A relocatable install (ECCE.app, which can be put anywhere) has wrappers
# that find ECCE_HOME relative to themselves; nothing from the build
# machine's paths may end up in it. Linux packages keep the fixed path.
option(ECCE_RELOCATABLE "Wrappers find ECCE_HOME relative to their own location" ${APPLE})
if(ECCE_RELOCATABLE)
file(RELATIVE_PATH ECCE_HOME_REL "${ECCE_WRAPPER_DESTINATION}" "${ECCE_HOME_DIR}")
file(READ ${CMAKE_SOURCE_DIR}/packaging/ecce-home.sh.in ECCE_HOME_SH)
string(REPLACE "@ECCE_HOME_REL@" "${ECCE_HOME_REL}" ECCE_HOME_SH "${ECCE_HOME_SH}")
string(STRIP "${ECCE_HOME_SH}" ECCE_HOME_SH)
else()
set(ECCE_HOME_SH "export ECCE_HOME=\${ECCE_HOME:-${ECCE_HOME_DIR}}")
endif()
# --- src/tdat -> libeccetdat.a ---
ecce_library(eccetdat
src/tdat/calcorg
src/tdat/chemistry
src/tdat/ffield
src/tdat/nwmdtask
src/tdat/properties
src/tdat/reaction
src/tdat/resources
)
# --- src/dsm -> 5 separate libraries, matching the old per-subdir mapping ---
ecce_library(eccexml src/dsm/chemistry src/dsm/xml)
ecce_library(eccecipc src/dsm/cipc)
if(WIN32)
target_link_libraries(eccecipc PUBLIC ws2_32)
endif()
find_package(OpenSSL REQUIRED)
target_link_libraries(eccecipc PUBLIC OpenSSL::SSL OpenSSL::Crypto)
ecce_library(eccedav src/dsm/dav)
ecce_library(eccedsi src/dsm/edsiimpl)
ecce_library(eccefaces src/dsm/faces)
# --- src/viz -> libeccevizsg.a ---
ecce_library(eccevizsg
src/viz/atomnodes
src/viz/nodes
src/viz/propsgcommands
src/viz/sgcommands
)
# --- src/comm -> 4 separate libraries ---
ecce_library(eccecomm src/comm/commtools)
ecce_library(eccecommxt src/comm/commxt)
ecce_library(eccercmd src/comm/rcommand)
# SshTransport needs libssh >= 0.10; without it the glob's copy is dropped
# and nothing else changes.
pkg_check_modules(LIBSSH IMPORTED_TARGET libssh>=0.10)
# ssh machines need libssh or the OpenSSH client; a build without libssh would
# only have the second, so configuration fails unless -DECCE_REQUIRE_LIBSSH=OFF.
option(ECCE_REQUIRE_LIBSSH "Fail configuration when libssh >= 0.10 is not found" ON)
if(ECCE_REQUIRE_LIBSSH AND NOT LIBSSH_FOUND)
message(FATAL_ERROR "ECCE_REQUIRE_LIBSSH is ON but libssh >= 0.10 was not found (install libssh-dev / libssh-devel)")
endif()
if(LIBSSH_FOUND)
target_link_libraries(eccercmd PUBLIC PkgConfig::LIBSSH)
target_compile_definitions(eccercmd PUBLIC ECCE_HAVE_LIBSSH=1)
else()
get_target_property(_rcmd_srcs eccercmd SOURCES)
list(FILTER _rcmd_srcs EXCLUDE REGEX "/SshTransport\\.C$")
set_property(TARGET eccercmd PROPERTY SOURCES ${_rcmd_srcs})
endif()
# --- src/inv -> libecceinv.a + libeccemoiv.a (libeccewxinv.a needs wx, TODO) ---
# Old build's src/inv/flclient/Makefile adds `pkg-config --cflags-only-I freetype2`
# on top of the baseline include dir: some FreeType headers (ft2build.h) live at
# the top of the freetype2 include tree, others (ftoutln.h etc, used elsewhere in
# this codebase) live one level down - both are needed.
# Same Homebrew-path gap as FREETYPE_UNQUALIFIED_INCLUDE_DIR above.
find_path(FREETYPE_ROOT_INCLUDE_DIR ft2build.h
PATH_SUFFIXES freetype2
PATHS /usr/include/freetype2 /usr/include
/opt/homebrew/include/freetype2
/usr/local/include/freetype2)
if(NOT FREETYPE_ROOT_INCLUDE_DIR)
message(FATAL_ERROR "FreeType's ft2build.h not found -- searched the usual Linux and Homebrew locations")
endif()
if(ECCE_USE_COIN)
# Only the FreeType font layer (flclient) is kept from the vendored core.
ecce_library(ecceinv src/inv/flclient)
target_compile_definitions(ecceinv PRIVATE NDEBUG)
target_include_directories(ecceinv PRIVATE ${FREETYPE_ROOT_INCLUDE_DIR})
target_link_libraries(ecceinv PUBLIC ${COIN_LIBRARY} OpenGL::GL OpenGL::GLU)
else()
ecce_library(ecceinv
src/inv/dbelements
src/inv/dbengines
src/inv/dbfields
src/inv/dbnodes
src/inv/dbsb
src/inv/dbso
src/inv/dbupgraders
src/inv/flclient
src/inv/image
src/inv/interaction
src/inv/nodekits
)
target_compile_definitions(ecceinv PRIVATE NDEBUG)
target_link_libraries(ecceinv PRIVATE OpenGL::GL OpenGL::GLU)
target_include_directories(ecceinv PRIVATE ${FREETYPE_ROOT_INCLUDE_DIR})
endif()
ecce_library(eccemoiv src/inv/moiv)
target_compile_definitions(eccemoiv PRIVATE NDEBUG)
target_link_libraries(eccemoiv PRIVATE OpenGL::GL OpenGL::GLU)
# ------------------------------------------------------------------------
# wxWidgets 2.8 -> 3.2 port (in progress). See
# claude/ecce-modernization-status.md in the project docs for what's done.
# ------------------------------------------------------------------------
# --- src/inv/wxinv -> libeccewxinv.a (Open Inventor / wxWidgets bridge) ---
ecce_library(eccewxinv src/inv/wxinv)
target_compile_definitions(eccewxinv PRIVATE NDEBUG ${wxWidgets_DEFINITIONS})
target_include_directories(eccewxinv PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(eccewxinv PRIVATE ${wxWidgets_LIBRARIES} OpenGL::GL OpenGL::GLU)
if(ECCE_USE_COIN AND ECCE_GL_X11)
find_package(OpenGL REQUIRED COMPONENTS EGL)
target_link_libraries(eccewxinv PUBLIC OpenGL::EGL ${CMAKE_DL_LIBS})
endif()
# --- src/wxviz -> libeccewxviz.a ---
ecce_library(eccewxviz src/wxviz/viewer src/wxviz/viztools)
target_compile_definitions(eccewxviz PRIVATE ${wxWidgets_DEFINITIONS})
target_include_directories(eccewxviz PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(eccewxviz PRIVATE ${wxWidgets_LIBRARIES} OpenGL::GL OpenGL::GLU)
# --- src/wxgui -> 5 separate libraries, matching the old per-subdir mapping ---
ecce_library(eccewxgui
src/wxgui/ewxClasses
src/wxgui/jms
src/wxgui/pertable
src/wxgui/wxdialogs
src/wxgui/wxtools
)
target_compile_definitions(eccewxgui PRIVATE ${wxWidgets_DEFINITIONS})
target_include_directories(eccewxgui PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(eccewxgui PRIVATE ${wxWidgets_LIBRARIES})
# ewxApp.C installs a g_log_set_writer_func() filter for a known-benign
# wxWidgets/GTK3 backend warning (see the comment there) -- needs GLib's
# own headers directly, which wxWidgets_INCLUDE_DIRS doesn't expose.
# GTK only: wx's macOS and Windows ports do not use GLib.
if(NOT APPLE)
pkg_check_modules(GLIB2 REQUIRED glib-2.0)
target_include_directories(eccewxgui PRIVATE ${GLIB2_INCLUDE_DIRS})
target_link_libraries(eccewxgui PRIVATE ${GLIB2_LIBRARIES})
endif()
# ewxRaiseWindow() (ewxWindowUtils.C) calls gtk_window_present*() and, on an
# X11 display only, gdk_x11_get_server_time() (#120); needs gtk+-3.0 headers
# and library, same as eccewxplotctrl below.
pkg_check_modules(GTK3 QUIET gtk+-3.0)
if(GTK3_FOUND)
target_include_directories(eccewxgui PRIVATE ${GTK3_INCLUDE_DIRS})
target_link_libraries(eccewxgui PRIVATE ${GTK3_LIBRARIES})
endif()
# WindowShot.C reads a window back from the window server on macOS.
if(APPLE)
target_link_libraries(eccewxgui PRIVATE "-framework ApplicationServices")
endif()
ecce_library(eccewxguicomm src/wxgui/comm)
target_compile_definitions(eccewxguicomm PRIVATE ${wxWidgets_DEFINITIONS})
target_include_directories(eccewxguicomm PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(eccewxguicomm PRIVATE ${wxWidgets_LIBRARIES})
ecce_library(eccewxguimd src/wxgui/mdtools)
target_compile_definitions(eccewxguimd PRIVATE ${wxWidgets_DEFINITIONS})
target_include_directories(eccewxguimd PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(eccewxguimd PRIVATE ${wxWidgets_LIBRARIES})
ecce_library(eccewxplotctrl src/wxgui/wxplotctrl)
target_compile_definitions(eccewxplotctrl PRIVATE ${wxWidgets_DEFINITIONS})
target_include_directories(eccewxplotctrl PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(eccewxplotctrl PRIVATE ${wxWidgets_LIBRARIES})
# Old build's src/wxgui/wxplotctrl/Makefile adds `pkg-config --cflags-only-I
# gtk+-2.0` - this build targets wx3.2's GTK3 backend, so gtk+-3.0 is the
# equivalent (the old gtk+-2.0 dev package isn't even installed here).
pkg_check_modules(GTK3 QUIET gtk+-3.0)
if(GTK3_FOUND)
target_include_directories(eccewxplotctrl PRIVATE ${GTK3_INCLUDE_DIRS})
endif()
ecce_library(eccewxthings src/wxgui/wxthings)
target_compile_definitions(eccewxthings PRIVATE ${wxWidgets_DEFINITIONS})
target_include_directories(eccewxthings PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(eccewxthings PRIVATE ${wxWidgets_LIBRARIES})
# ------------------------------------------------------------------------
# src/apps -> the final executables. Each old src/apps/<name>/Makefile
# defined PROGRAMS (usually one, matching the directory name) built from
# every .C file in that directory, plus an ECCE_LIBS list of which of the
# static libraries above to link against - see src/apps/<name>/Makefile in
# git history for the exact old lists these were transcribed from. A few
# apps (davutils, ecmd, jobstore) never included Makefile.wx at all and
# have no wx dependency; the rest all do. builder and vizthumbnail also
# pull in Makefile.gl (they link the Open Inventor/visualization stack).
# ------------------------------------------------------------------------
# Helper: define an executable from every .C source file in one directory.
# link_libs are this app's own ECCE_LIBS list (as CMake target names, i.e.
# without the old "-l" prefix - note libecceedsi.a is the CMake target
# "eccedsi" here, not "ecceedsi", see the src/dsm section above).
function(ecce_app name dir)
cmake_parse_arguments(ECCE_APP "WX;GL" "" "LINK" ${ARGN})
file(GLOB _srcs CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/${dir}/*.C)
add_executable(${name} ${_srcs})
target_include_directories(${name} PRIVATE ${XercesC_INCLUDE_DIRS})
if(ECCE_APP_WX)
target_compile_definitions(${name} PRIVATE ${wxWidgets_DEFINITIONS})
target_include_directories(${name} PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(${name} PRIVATE ${wxWidgets_LIBRARIES})
endif()
if(ECCE_APP_GL)
target_link_libraries(${name} PRIVATE OpenGL::GL OpenGL::GLU)
endif()
if(WIN32)
# The static libraries reference each other in cycles; GNU ld rescans a group.
target_link_libraries(${name} PRIVATE
"$<LINK_GROUP:RESCAN,${ECCE_APP_LINK}>" ${XercesC_LIBRARIES})
else()
target_link_libraries(${name} PRIVATE ${ECCE_APP_LINK} ${XercesC_LIBRARIES})
endif()
endfunction()
# --- apps with no wx dependency ---
ecce_app(load_tgbs src/apps/davutils
LINK eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(ecmd src/apps/ecmd
LINK eccercmd eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
# jobstore builds two independent single-file programs from this directory,
# each with its own main() - not combined into one binary (matches the old
# Makefile's "multiple PROGRAMS -> each from its own matching .o" rule).
add_executable(eccejobmaster src/apps/jobstore/eccejobmaster.C)
target_include_directories(eccejobmaster PRIVATE ${XercesC_INCLUDE_DIRS})
target_link_libraries(eccejobmaster PRIVATE
eccecommxt eccercmd eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil
${XercesC_LIBRARIES})
# The wrappers ask it which data mode a session is in (#216).
add_executable(ecce-localdata src/apps/localdata/ecce-localdata.C)
target_include_directories(ecce-localdata PRIVATE ${XercesC_INCLUDE_DIRS})
target_link_libraries(ecce-localdata PRIVATE ecceutil ${XercesC_LIBRARIES})
# An MO's atomic-orbital composition from a calculation folder (#161).
# Installed as bin/mocomp; its wrapper is ecce-mocomp like every CLI app's.
add_executable(mocomp src/apps/mocomp/mocomp.C)
target_include_directories(mocomp PRIVATE ${XercesC_INCLUDE_DIRS})
target_link_libraries(mocomp PRIVATE
eccedsi eccedav eccecipc eccefaces eccexml eccetdat eccedsi eccexml ecceutil
${XercesC_LIBRARIES})
# flock(1) for the session scripts where util-linux is absent (macOS).
if(NOT WIN32) # the Windows client has no session scripts (#133)
add_executable(ecce-flock src/apps/flock/ecce-flock.c)
endif()
# The server half of "ecce -admin" on a -remote client (SiteRequest).
add_executable(ecce-site-admin src/apps/siteadmin/ecce-site-admin.C)
target_link_libraries(ecce-site-admin PRIVATE eccetdat ecceutil)
add_executable(eccejobstore src/apps/jobstore/eccejobstore.C)
target_include_directories(eccejobstore PRIVATE ${XercesC_INCLUDE_DIRS})
target_link_libraries(eccejobstore PRIVATE
eccecommxt eccercmd eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil
${XercesC_LIBRARIES})
# --- wx apps ---
ecce_app(basistool src/apps/basistool WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(calced src/apps/calced WX
LINK eccecomm eccercmd eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(dirdyed src/apps/dirdyed WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(gateway src/apps/gateway WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(launcher src/apps/launcher WX
LINK eccecommxt eccecomm eccercmd eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(machbrowser src/apps/machbrowser WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccercmd eccetdat ecceutil)
ecce_app(machregister src/apps/machregister WX
# eccercmd for RCommand::localityNote (#144), the same decision the launch makes.
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccercmd eccetdat ecceutil)
ecce_app(mddynamics src/apps/mddynamics WX
LINK eccewxguimd eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(mdenergy src/apps/mdenergy WX
LINK eccewxguimd eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(mdoptimize src/apps/mdoptimize WX
LINK eccewxguimd eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(mdprepare src/apps/mdprepare WX
LINK eccewxgui eccewxplotctrl eccewxthings eccecommxt eccecomm eccercmd eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(msgdialog src/apps/messagedialog WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(metadyn src/apps/metadyn WX
LINK eccecomm eccercmd eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(organizer src/apps/organizer WX
LINK eccewxguicomm eccecommxt eccecomm eccercmd eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(hostkeydialog src/apps/hostkeydialog WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(passdialog src/apps/passdialog WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(pertable src/apps/pertable WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(polyed src/apps/polyrate WX
LINK eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
ecce_app(solvate src/apps/solvate WX
LINK eccecomm eccercmd eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil)
# Native replacement for the wxPython Details dialogs (pilot): reads the
# .dlg files next to scripts/codereg/*.py. wx only, so it links nothing of
# ECCE's; JCode::getTheoryRunTypeEditorNames starts it when ECCE_NATIVE_DIALOGS
# is set. Not in ECCE_GUI_APPS: no wrapper script, it is never run by hand.
add_executable(ecce-dialog src/apps/codereg-dialog/ecce-dialog.cpp)
target_compile_definitions(ecce-dialog PRIVATE ${wxWidgets_DEFINITIONS})
target_include_directories(ecce-dialog PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_link_libraries(ecce-dialog PRIVATE ${wxWidgets_LIBRARIES})
if(WIN32)
set_target_properties(ecce-dialog PROPERTIES WIN32_EXECUTABLE ON)
endif()
install(TARGETS ecce-dialog RUNTIME DESTINATION bin COMPONENT client)
# --- wx + GL apps ---
ecce_app(builder src/apps/builder WX GL
LINK eccewxguicomm eccewxviz eccewxinv eccevizsg eccemoiv ecceinv eccecommxt eccecomm eccercmd
eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil
${ECCE_X11_LIBS} jpeg freetype)
ecce_app(vizthumbnail src/apps/vizthumbnail WX GL
LINK eccewxviz eccewxinv eccevizsg eccemoiv ecceinv eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil ${ECCE_X11_LIBS} jpeg freetype)
# Headless scene renderer for comparing the vendored and Coin viewer builds
# (tools/coin/compare.sh); built only on request.
ecce_app(viewer-scenes tools/coin WX GL
LINK eccewxviz eccewxinv eccevizsg eccemoiv ecceinv eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil ${ECCE_X11_LIBS} jpeg freetype)
set_target_properties(viewer-scenes PROPERTIES EXCLUDE_FROM_ALL TRUE)
# Renders .rgb files through VizRender and converts them (tests/look/imageconv.py).
ecce_app(render-rgb tests/look/imageconv WX GL
LINK eccewxviz eccewxinv eccevizsg eccemoiv ecceinv eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil ${ECCE_X11_LIBS} jpeg freetype)
set_target_properties(render-rgb PROPERTIES EXCLUDE_FROM_ALL TRUE)
# Paints the spectrum canvas onto a bitmap (tests/spectrum, #214); `ninja
# spectrum-render`, needs a display (xvfb-run).
ecce_app(spectrum-render tools/spectrum WX LINK eccetdat ecceutil)
set_target_properties(spectrum-render PROPERTIES EXCLUDE_FROM_ALL TRUE)
target_include_directories(spectrum-render PRIVATE ${CMAKE_SOURCE_DIR}/src/apps/builder)
# Coin only: the EGL offscreen path with no wx and no display.
if(ECCE_USE_COIN)
add_executable(offscreen-check EXCLUDE_FROM_ALL tools/coin/offscreen/offscreen-check.C)
target_link_libraries(offscreen-check PRIVATE eccewxinv ${COIN_LIBRARY} ${wxWidgets_LIBRARIES} OpenGL::GL)
target_include_directories(offscreen-check PRIVATE ${wxWidgets_INCLUDE_DIRS})
endif()
# Coin's glue display is the offscreen one, not an EGL X11 display (#237);
# ctest coin_egl_display. Exports eglglue_display, as an EGL-only Coin does.
if(ECCE_USE_COIN AND ECCE_GL_X11)
add_executable(egl-display-check tools/coin/offscreen/egl-display-check.C)
target_link_libraries(egl-display-check PRIVATE eccewxinv ${COIN_LIBRARY} ${wxWidgets_LIBRARIES} OpenGL::GL)
target_include_directories(egl-display-check PRIVATE ${wxWidgets_INCLUDE_DIRS})
set_target_properties(egl-display-check PROPERTIES ENABLE_EXPORTS ON)
endif()
# Frame-time benchmark for the molecule viewer (tools/viewer-bench); built
# only on request, by tools/viewer-bench/run.sh.
# It calls glX directly, so only where the viewer's GL is X11.
if(ECCE_GL_X11)
ecce_app(viewer-bench tools/viewer-bench WX GL
LINK eccewxviz eccewxinv eccevizsg eccemoiv ecceinv eccewxgui eccewxplotctrl eccewxthings eccedsi eccedav eccecipc eccefaces eccexml eccetdat ecceutil ${ECCE_X11_LIBS} jpeg freetype)
set_target_properties(viewer-bench PROPERTIES EXCLUDE_FROM_ALL TRUE)
endif()
# --- src/apps/symmetry -> 5 standalone Fortran executables, no wx involvement.
# Mirrors the old Makefile's "default:" target exactly (testnames is a
# dev/test-only program the old default build skipped - left out here too).
# Each program links only the specific .f/.f90 object files its old Makefile
# rule listed, not every source file in the directory (unlike ecce_app(),
# which links a whole directory - this old Makefile was per-program instead).
function(ecce_fortran_app name)
cmake_parse_arguments(ECCE_FAPP "" "" "SOURCES" ${ARGN})
add_executable(${name} ${ECCE_FAPP_SOURCES})
# Several of these programs independently compile the same spnames.f90 /
# spgen.f90 module sources - give each target its own .mod output
# directory so Ninja doesn't see two targets writing the same
# spnames.mod/spgen.mod file (they're identical content, but CMake/Ninja
# doesn't know that and refuses to build with a shared output).
set_target_properties(${name} PROPERTIES
Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${name}.mod)
# The Fortran runtime comes with the compiler, not the OS: link it in
# so the app bundles no libgfortran and its minimum macOS stays ours.
if(APPLE)
target_link_options(${name} PRIVATE -static-libgfortran -static-libgcc -static-libquadmath)
endif()
endfunction()
set(_sym_dir ${CMAKE_SOURCE_DIR}/src/apps/symmetry)
ecce_fortran_app(autosym
SOURCES ${_sym_dir}/autosym.f ${_sym_dir}/geom_hnd.f ${_sym_dir}/deter3.f ${_sym_dir}/errquit.f)
ecce_fortran_app(getfrag
SOURCES ${_sym_dir}/getfrag.f ${_sym_dir}/findfrag.f ${_sym_dir}/spnames.f90 ${_sym_dir}/spgen.f90
${_sym_dir}/deter3.f ${_sym_dir}/dctr.f ${_sym_dir}/gensym.f ${_sym_dir}/errquit.f)
ecce_fortran_app(genmol
SOURCES ${_sym_dir}/genmol.f ${_sym_dir}/dosymops.f ${_sym_dir}/spnames.f90 ${_sym_dir}/spgen.f90
${_sym_dir}/deter3.f ${_sym_dir}/dctr.f ${_sym_dir}/gensym.f ${_sym_dir}/errquit.f)
ecce_fortran_app(genmollat
SOURCES ${_sym_dir}/genmollat.f ${_sym_dir}/dosymops.f ${_sym_dir}/spnames.f90 ${_sym_dir}/spgen.f90
${_sym_dir}/deter3.f ${_sym_dir}/dctr.f ${_sym_dir}/gensym.f ${_sym_dir}/errquit.f)
# Added for the symmetry analysis behind the MO diagrams (#132): gensym
# already turns a group name into its operation matrices, and nothing
# outside these Fortran tools could reach them.
ecce_fortran_app(symops
SOURCES ${_sym_dir}/symops.f ${_sym_dir}/spnames.f90 ${_sym_dir}/spgen.f90
${_sym_dir}/deter3.f ${_sym_dir}/dctr.f ${_sym_dir}/gensym.f ${_sym_dir}/errquit.f)
ecce_fortran_app(cleansym
SOURCES ${_sym_dir}/cleansym.f ${_sym_dir}/sym_avg.f ${_sym_dir}/spnames.f90 ${_sym_dir}/spgen.f90
${_sym_dir}/deter3.f ${_sym_dir}/dctr.f ${_sym_dir}/gensym.f ${_sym_dir}/errquit.f)
# ------------------------------------------------------------------------
# The messaging gateway: packaging/gateway/ecce-gateway-* start a per-user
# mosquitto on a Unix socket (or point the processes at a central or shared
# broker) and write the broker file src/util/jms/MqttLink.C reads. The
# broker is the distribution's mosquitto package; nothing is built here.
# ------------------------------------------------------------------------
# Help content: BrowserHelp::initialize() (src/util/genutil/BrowserHelp.C)
# throws NullPointerException -- uncaught, crashing the whole app -- if
# ECCE_HELP isn't set in the environment when any Help button is clicked.
# None of the app wrapper scripts set it (an old gap, not a regression --
# the old scripts/runtime_setup this replaces apparently did). Extract the
# vendored help content this package already ships
# (data/admin/dataserver/help/eccehelp.tar) into the layout help.urls'
# entries expect (an "EcceHelp/" subdirectory containing homepage.html,
# etc. -- confirmed against the tarball's actual contents and against
# BrowserHelp::initialize()'s own p_filePrefix construction, which is
# hardcoded to ecceDataPath()/client/WebHelp/), then point ECCE_HELP at it
# in the wrapper scripts below. ECCE_HELP is an http:// URL served by the
# data server's Apache instance (see packaging/dataserver/httpd.conf.ecce's
# "/EcceHelp" Alias), not a raw file:// path -- the help content's own HTML
# uses absolute paths like "/EcceHelp/media/foo.gif" for every image and
# many links, which only resolve correctly against an HTTP server where
# "/EcceHelp" is a real URL root; opened as file://, a browser resolves
# that same absolute path against the filesystem root instead, breaking
# every embedded image. Entries in help.urls that need the CGI help
# backend (cgi-bin/help/cshelp, toolhelp) now work too -- see the
# ecce_help_cgi_patch step below, which patches the vendored Perl scripts'
# shebang and hardcoded PNNL path for this install, and
# ecce-dataserver-start, which seeds them into the per-user cgi-bin/
# alongside the pre-existing (still-unimplemented) account-creation CGI
# slot.
set(_ecce_help_tarball ${CMAKE_SOURCE_DIR}/data/admin/dataserver/help/eccehelp.tar)
if(EXISTS ${_ecce_help_tarball})
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/ecce-help-extracted/EcceHelp/homepage.html
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/ecce-help-extracted/EcceHelp
COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/ecce-help-extracted/EcceHelp
${CMAKE_COMMAND} -E tar xf ${_ecce_help_tarball}
# The vendored tarball itself ships 3 genuinely corrupt entries under
# basis/ and builder/ -- filenames containing literal HTML markup
# (quotes, "<", ">", spaces, e.g. `overview_top"> <!-- #begineditable
# "title.html`), not real help pages. Confirmed via `tar tf` against
# the tarball directly -- this is decades-old corruption in the
# vendored PNNL content itself, not something this build introduced.
# Harmless for a DEB build (dpkg-deb tolerates the odd filename) but
# a real, reproducible CI failure for RPM packaging specifically
# ("CPack Error: Problem compressing the directory" -- rpmbuild's
# file-list handling rejects them outright), and not guaranteed safe
# on every filesystem/locale a DEB build might run under either.
# None of these 3 files are reachable from help.urls or any real
# navigation path (their "content" is a stray HTML comment fragment,
# not a page), so deleting them costs nothing.
COMMAND bash -c "find '${CMAKE_BINARY_DIR}/ecce-help-extracted/EcceHelp' -name '*begineditable*' -delete"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Extracting vendored ECCE help content"
)
add_custom_target(ecce_help ALL
DEPENDS ${CMAKE_BINARY_DIR}/ecce-help-extracted/EcceHelp/homepage.html)
# The vendored toolhelp/cshelp CGI scripts (context-sensitive help,
# invoked from within ECCE apps) hardcode PNNL's own 1990s server path
# and Perl location. Neither script depends on CGI.pm (unlike the data
# server's still-unported account-creation CGI) -- just the ancient but
# still-bundled getopts.pl -- so patching these two values is enough to
# make them work as-is against this install.
set(_help_cgi_dir ${CMAKE_BINARY_DIR}/ecce-help-extracted/EcceHelp/cgi-bin)
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/ecce-help-extracted/.help-cgi-patched
COMMAND bash ${CMAKE_SOURCE_DIR}/packaging/dataserver/patch-help-cgi.sh ${_help_cgi_dir}
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/ecce-help-extracted/.help-cgi-patched
DEPENDS ${CMAKE_BINARY_DIR}/ecce-help-extracted/EcceHelp/homepage.html
${CMAKE_SOURCE_DIR}/packaging/dataserver/patch-help-cgi.sh
COMMENT "Patching vendored help CGI scripts (shebang, help_dir) for this install"
)
add_custom_target(ecce_help_cgi_patch ALL
DEPENDS ${CMAKE_BINARY_DIR}/ecce-help-extracted/.help-cgi-patched)
# Client content: local mode (#216) opens these pages as files, with no
# data server. A server serves the same files (httpd.conf.ecce's
# "/EcceHelp" Alias) and seeds its help CGIs from them, at this path,
# and ecce-server depends on ecce-client, so it always has them.
install(DIRECTORY ${CMAKE_BINARY_DIR}/ecce-help-extracted/EcceHelp
DESTINATION data/client/WebHelp
COMPONENT client)
set(ECCE_HELP_AVAILABLE TRUE)
else()
message(WARNING "No vendored help tarball at ${_ecce_help_tarball} - "
"Help will still work (won't crash) but ECCE_HELP will "
"point at a location with no content.")
set(ECCE_HELP_AVAILABLE FALSE)
endif()
if(EXISTS ${CMAKE_SOURCE_DIR}/siteconfig/DataServers)
file(READ ${CMAKE_SOURCE_DIR}/siteconfig/DataServers _dataservers_contents)
# The checked-in template points at the
# real PNNL production server; repoint it at the data server this
# package installs and starts locally (see ecce-dataserver-start for
# the matching port). Both the default <Url> and the <BasisSet> URL
# share this hostname, and nothing else in the file does, so one
# substring replace covers both.
string(REPLACE "eccetera.emsl.pnl.gov" "localhost"
_dataservers_contents "${_dataservers_contents}")
file(WRITE ${CMAKE_BINARY_DIR}/siteconfig-local/DataServers "${_dataservers_contents}")
endif()
if(EXISTS ${CMAKE_SOURCE_DIR}/siteconfig/site_runtime)
file(READ ${CMAKE_SOURCE_DIR}/siteconfig/site_runtime _site_runtime_contents)
# ECCE_AUTO_ACCOUNTS drives EDSIServerCentral::checkServerSetup()'s
# self-service account-creation POST against cgi-bin/ecce_accounts,
# which this package doesn't install (the Perl CGI auto-provisioning
# flow is deliberately deferred, see packaging/dataserver/ -- a missing
# CGI degrades gracefully in the client, but there's no reason to
# attempt a request that can never succeed). Flip it off; accounts are
# created with ecce-dataserver-adduser instead.
string(REGEX REPLACE
"ECCE_AUTO_ACCOUNTS[ \t]+yes"
"ECCE_AUTO_ACCOUNTS no"
_site_runtime_contents "${_site_runtime_contents}")
file(WRITE ${CMAKE_BINARY_DIR}/siteconfig-local/site_runtime "${_site_runtime_contents}")
endif()
# Single directory install for everything in siteconfig/ *except* the
# files rewritten above, which install from their resolved
# siteconfig-local/ copies instead. (Deliberately one combined
# install(DIRECTORY) rather than one per rewritten file above -- two
# separate install(DIRECTORY siteconfig/ ...) calls with different
# exclude sets would both run at install time and race on which version
# of the non-excluded files wins.)
# siteconfig/ is entirely client-side config: it tells a CLIENT install
# where to find servers (DataServers, RemoteServer/),
# what compute resources/queues exist (Machines, Queues, CONFIG-Examples),
# and how it should behave (site_runtime). Nothing under server/ reads
# any of it -- the data server and broker are configured from
# packaging/dataserver and packaging/gateway instead. So it goes whole
# into the client component with no split needed.
# The Windows and macOS clients do not ship the example "dummy" machine
# (manual submission to an unreachable cluster): a desktop install starts
# with localhost alone.
set(_siteconfig_excludes)
if(WIN32 OR APPLE)
file(READ ${CMAKE_SOURCE_DIR}/siteconfig/Machines _machines)
string(REGEX REPLACE "# A machine ECCE never contacts[^\n]*\n(#[^\n]*\n)*dummy\t[^\n]*\n" ""
_machines "${_machines}")
file(WRITE ${CMAKE_BINARY_DIR}/siteconfig-local/Machines "${_machines}")
file(READ ${CMAKE_SOURCE_DIR}/siteconfig/Queues _queues)
string(REPLACE "Queues: localhost dummy" "Queues: localhost" _queues "${_queues}")
string(REGEX REPLACE "\ndummy\\|[^\n]*" "" _queues "${_queues}")
file(WRITE ${CMAKE_BINARY_DIR}/siteconfig-local/Queues "${_queues}")
install(FILES ${CMAKE_BINARY_DIR}/siteconfig-local/Machines
${CMAKE_BINARY_DIR}/siteconfig-local/Queues
DESTINATION siteconfig COMPONENT client)
set(_siteconfig_excludes PATTERN "Machines" EXCLUDE PATTERN "Queues" EXCLUDE
PATTERN "CONFIG.dummy" EXCLUDE PATTERN "dummy.Q" EXCLUDE)
endif()
install(DIRECTORY ${CMAKE_SOURCE_DIR}/siteconfig/ DESTINATION siteconfig
COMPONENT client
PATTERN "RemoteServer" EXCLUDE
PATTERN "DataServers" EXCLUDE
PATTERN "site_runtime" EXCLUDE
${_siteconfig_excludes})
install(FILES ${CMAKE_BINARY_DIR}/siteconfig-local/DataServers
${CMAKE_BINARY_DIR}/siteconfig-local/site_runtime
DESTINATION siteconfig
COMPONENT client)
# ecce-gateway-{start,stop,status,reap}: start and stop the session's
# mosquitto broker and keep the broker files. Client-side, since a client
# on its own machine runs its own broker unless it uses -remote.
install(PROGRAMS
${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-gateway-start
${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-gateway-stop
${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-gateway-status
${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-gateway-reap
${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-find-mosquitto
${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-first-start
${CMAKE_SOURCE_DIR}/packaging/windows/ecce-broker-win
${CMAKE_SOURCE_DIR}/packaging/nwchem/ecce-nwchem-datadir
DESTINATION bin
COMPONENT client)
# Sourced by the scripts above, the wrappers and `ecce` (#233).
install(FILES ${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-session-lib.sh
DESTINATION bin
COMPONENT client)
# Deployment mode 3, the site's shared broker (GETTING_STARTED.md,
# "Deployment modes"). ecce-broker-setup writes siteconfig/SharedBroker,
# which the clients read, so it goes with them; ecce-broker-run and the
# unit run the broker, so they go with its config. The unit is installed
# beside that config rather than into /usr/lib/systemd/system, so a
# non-root prefix install still works; ecce-broker-setup prints the
# `systemctl link` for it.
install(PROGRAMS ${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-broker-setup
DESTINATION bin
COMPONENT client)
install(PROGRAMS ${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-broker-run
DESTINATION bin
COMPONENT server)
if(NOT APPLE AND NOT WIN32) # no systemd there
configure_file(${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-broker.service.in
${CMAKE_BINARY_DIR}/systemd/ecce-broker.service @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/systemd/ecce-broker.service
DESTINATION server/systemd
COMPONENT server)
endif()
# The broker plugin that checks logins against the data server's users
# file (a central server's broker, ecce-gateway-start). Needs mosquitto's
# plugin header and apr-util, whose apr_password_validate reads htpasswd's
# hash formats.
if(NOT APPLE AND NOT WIN32) # macOS and Windows run no central server
pkg_check_modules(APRUTIL REQUIRED IMPORTED_TARGET apr-util-1)
find_path(MOSQUITTO_PLUGIN_INCLUDE_DIR mosquitto_plugin.h REQUIRED)
add_library(ecce_users_auth MODULE src/mqttauth/ecce_users_auth.c)
set_target_properties(ecce_users_auth PROPERTIES PREFIX "")
target_include_directories(ecce_users_auth PRIVATE ${MOSQUITTO_PLUGIN_INCLUDE_DIR})
target_link_libraries(ecce_users_auth PRIVATE PkgConfig::APRUTIL)
install(TARGETS ecce_users_auth LIBRARY DESTINATION server COMPONENT server)
endif()
# The per-user access rules of a mosquitto serving clients over TCP: the
# shared broker's and a central server's.
install(FILES ${CMAKE_SOURCE_DIR}/packaging/gateway/ecce-mosquitto.acl
DESTINATION server RENAME mosquitto.acl
COMPONENT server)
set(_bs_wrapper ${CMAKE_BINARY_DIR}/wrappers/ecce-broker-setup)
file(WRITE ${_bs_wrapper}
"#!/bin/bash
${ECCE_HOME_SH}
exec \"$ECCE_HOME/bin/ecce-broker-setup\" \"$@\"
")
install(PROGRAMS ${_bs_wrapper} DESTINATION ${ECCE_WRAPPER_DESTINATION} COMPONENT client)
# Also put the gateway control scripts on PATH directly (like the ecce-<app>
# wrappers) so `ecce-gateway-status` etc. work without needing $ECCE_HOME.
foreach(_gw start stop status reap)
set(_gw_wrapper ${CMAKE_BINARY_DIR}/wrappers/ecce-gateway-${_gw})
file(WRITE ${_gw_wrapper}
"#!/bin/bash
${ECCE_HOME_SH}
export ECCE_REALUSERHOME=\${ECCE_REALUSERHOME:-$HOME}
exec \"$ECCE_HOME/bin/ecce-gateway-${_gw}\" \"$@\"
")
install(PROGRAMS ${_gw_wrapper} DESTINATION ${ECCE_WRAPPER_DESTINATION} COMPONENT client)
endforeach()
# ------------------------------------------------------------------------
# ECCE data server (EDSI/WebDAV) - the other half of old ECCE's server
# side, independent of the JMS gateway above. Runs as a per-user,
# non-root Debian apache2 instance under $ECCE_REALUSERHOME/.ECCE/
# dataserver -- see packaging/dataserver/httpd.conf.ecce and
# ecce-dataserver-start for the full rationale. Requires the apache2 and
# apache2-utils packages at runtime (see CPACK_DEBIAN_PACKAGE_DEPENDS
# below); nothing to vendor/extract here since both are ordinary Debian
# packages.
# ------------------------------------------------------------------------
# The dataserver's own start/stop/status/adduser: only meaningful on a
# machine actually running the Apache instance, so these -- and the
# Apache config they resolve -- are server-only.
install(PROGRAMS
${CMAKE_SOURCE_DIR}/packaging/dataserver/ecce-dataserver-start
${CMAKE_SOURCE_DIR}/packaging/dataserver/ecce-dataserver-stop
${CMAKE_SOURCE_DIR}/packaging/dataserver/ecce-dataserver-status
${CMAKE_SOURCE_DIR}/packaging/dataserver/ecce-dataserver-adduser
${CMAKE_SOURCE_DIR}/packaging/dataserver/ecce-site-publish
DESTINATION bin
COMPONENT server)
install(FILES ${CMAKE_SOURCE_DIR}/packaging/dataserver/httpd.conf.ecce
DESTINATION server/httpd-conf
COMPONENT server)
# ecce-remote-setup and ecce-diagnose, by contrast, run on and describe
# the CLIENT installation (ecce-remote-setup writes this client's own
# siteconfig/RemoteServer/; ecce-diagnose collects this install's own
# state) -- they belong with ecce-client even though they live under
# packaging/dataserver/ and packaging/ for historical reasons.
install(PROGRAMS
${CMAKE_SOURCE_DIR}/packaging/dataserver/ecce-remote-setup
${CMAKE_SOURCE_DIR}/packaging/ecce-diagnose
DESTINATION bin
COMPONENT client)
# ecce-site-publish is a server program too; ecce-site-admin ships with the
# client (a server has both) and must be on the PATH an ssh command gets.
set(_pub_wrapper ${CMAKE_BINARY_DIR}/wrappers/ecce-site-publish)
file(WRITE ${_pub_wrapper}
"#!/bin/bash
${ECCE_HOME_SH}
export ECCE_REALUSERHOME=\${ECCE_REALUSERHOME:-$HOME}
exec \"$ECCE_HOME/bin/ecce-site-publish\" \"$@\"
")
install(PROGRAMS ${_pub_wrapper} DESTINATION ${ECCE_WRAPPER_DESTINATION} COMPONENT server)
set(_sadm_wrapper ${CMAKE_BINARY_DIR}/wrappers/ecce-site-admin)
file(WRITE ${_sadm_wrapper}
"#!/bin/bash
${ECCE_HOME_SH}
export ECCE_REALUSERHOME=\${ECCE_REALUSERHOME:-$HOME}
exec \"$ECCE_HOME/bin/ecce-site-admin\" \"$@\"
")
install(PROGRAMS ${_sadm_wrapper} DESTINATION ${ECCE_WRAPPER_DESTINATION} COMPONENT client)
foreach(_ds start stop status adduser)
set(_ds_wrapper ${CMAKE_BINARY_DIR}/wrappers/ecce-dataserver-${_ds})
file(WRITE ${_ds_wrapper}
"#!/bin/bash
${ECCE_HOME_SH}
export ECCE_REALUSERHOME=\${ECCE_REALUSERHOME:-$HOME}
export ECCE_REALUSER=\${ECCE_REALUSER:-\$(id -un)}
exec \"$ECCE_HOME/bin/ecce-dataserver-${_ds}\" \"$@\"
")
install(PROGRAMS ${_ds_wrapper} DESTINATION ${ECCE_WRAPPER_DESTINATION} COMPONENT server)
endforeach()
# The same wrapper for the central-server setup helper, so an
# administrator can type "ecce-remote-setup <host>" without knowing
# where the installation lives.
# Same for the diagnostic collector, which is only ever run by
# somebody who has already hit a problem and should not also have to
# find out where ECCE was installed.
set(_diag_wrapper ${CMAKE_BINARY_DIR}/wrappers/ecce-diagnose)
file(WRITE ${_diag_wrapper}
"#!/bin/bash
${ECCE_HOME_SH}
exec \"$ECCE_HOME/bin/ecce-diagnose\" \"$@\"
")
install(PROGRAMS ${_diag_wrapper} DESTINATION ${ECCE_WRAPPER_DESTINATION} COMPONENT client)
set(_remote_wrapper ${CMAKE_BINARY_DIR}/wrappers/ecce-remote-setup)
file(WRITE ${_remote_wrapper}
"#!/bin/bash
${ECCE_HOME_SH}
exec \"$ECCE_HOME/bin/ecce-remote-setup\" \"$@\"
")
install(PROGRAMS ${_remote_wrapper} DESTINATION ${ECCE_WRAPPER_DESTINATION} COMPONENT client)
# ------------------------------------------------------------------------
# Install rules. Everything installs under /opt/ecce (see
# CPACK_PACKAGING_INSTALL_PREFIX below) - the compiled apps still expect
# an ECCE_HOME pointing at a directory with bin/ and data/ as siblings
# (see src/util/genutil/Ecce.C, SFile.C's $ECCE_HOME expansion), which a
# split FHS layout (bin in /usr/bin, data in /usr/share/...) doesn't give
# them without a lot of path-handling surgery this session hasn't done.
# ------------------------------------------------------------------------
set(ECCE_GUI_APPS
basistool calced dirdyed gateway launcher machbrowser machregister
mddynamics mdenergy mdoptimize mdprepare msgdialog metadyn organizer
passdialog hostkeydialog pertable polyed solvate builder vizthumbnail)
set(ECCE_CLI_APPS
load_tgbs ecmd eccejobmaster eccejobstore ecce-localdata ecce-site-admin mocomp
autosym getfrag genmol genmollat cleansym symops)
if(NOT WIN32)
list(APPEND ECCE_CLI_APPS ecce-flock)
endif()