diff --git a/CMakeLists.txt b/CMakeLists.txt index 255b94dfc99..1de49634af8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,19 +176,7 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) if(WITH_FHS) file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_DEMODIR} ${RUNTIME_GISBASE}/demolocation SYMBOLIC) - file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_FONTSDIR} ${RUNTIME_GISBASE}/fonts - SYMBOLIC) - file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_ETCDIR}/colors - ${RUNTIME_GISBASE}/etc/colors SYMBOLIC) - file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_ETCDIR}/colors.desc - ${RUNTIME_GISBASE}/etc/colors.desc SYMBOLIC) - file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_ETCDIR}/element_list - ${RUNTIME_GISBASE}/etc/element_list SYMBOLIC) - file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_ETCDIR}/renamed_options - ${RUNTIME_GISBASE}/etc/renamed_options SYMBOLIC) - file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_ETCDIR}/VERSIONNUMBER - ${RUNTIME_GISBASE}/etc/VERSIONNUMBER SYMBOLIC) - file(MAKE_DIRECTORY "${GISBASE}/gui/wxpython") + file(MAKE_DIRECTORY "${RUNTIME_GISBASE}/gui/wxpython") file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_GUIDIR}/wxpython/xml ${RUNTIME_GISBASE}/gui/wxpython/xml SYMBOLIC) endif() @@ -228,6 +216,17 @@ if(WIN32) ${CMAKE_COMMAND} -E env "PATH=${BIN_DIR}${sep}${SCRIPTS_DIR}${sep}${env_path}${sep}${LIB_DIR}" "PYTHONPATH=${ETC_PYTHON_DIR}${sep}${GUI_WXPYTHON_DIR}${sep}$ENV{PYTHONPATH}" "GRASS_PYTHON=${PYTHON_EXECUTABLE}" "GISBASE=${RUN_GISBASE_NATIVE}" "GISRC=${GISRC}" "LC_ALL=C" "LANG=C" + "GRASS_COLORSDIR=${RUNTIME_GRASS_COLORSDIR}" + "GRASS_DOCDIR=${RUNTIME_GRASS_DOCDIR}" + "GRASS_ETCDIR=${RUNTIME_GRASS_ETCDIR}" + "GRASS_FONTSDIR=${RUNTIME_GRASS_FONTSDIR}" + "GRASS_GRAPHICSDIR=${RUNTIME_GRASS_GRAPHICSDIR}" + "GRASS_GUIRESDIR=${RUNTIME_GRASS_GUIRESDIR}" + "GRASS_GUISCRIPTDIR=${RUNTIME_GRASS_GUISCRIPTDIR}" + "GRASS_GUIWXDIR=${GUI_WXPYTHON_DIR}" + "GRASS_LOCALEDIR=${RUNTIME_GRASS_LOCALEDIR}" + "GRASS_MKDOCSDIR=${RUNTIME_GRASS_MKDOCSDIR}" + "GRASS_SHAREDIR=${RUNTIME_GRASS_SHAREDIR}" "ARCH=${BUILD_ARCH}" "ARCH_DISTDIR=${RUN_GISBASE_NATIVE}" "LANGUAGE=C" "MODULE_TOPDIR=${MODULE_TOPDIR}" "HTMLDIR=${DOC_DIR}" "LC_ALL=C" "LANG=C" @@ -244,6 +243,17 @@ else() "PYTHONPATH=${ETC_PYTHON_DIR}${sep}${GUI_WXPYTHON_DIR}${sep}$ENV{PYTHONPATH}" "LD_LIBRARY_PATH=${LIB_DIR}${sep}$ENV{LD_LIBRARY_PATH}" "GISBASE=${RUN_GISBASE_NATIVE}" "GISRC=${GISRC}" "LC_ALL=C" "LANG=C" + "GRASS_COLORSDIR=${RUNTIME_GRASS_COLORSDIR}" + "GRASS_DOCDIR=${RUNTIME_GRASS_DOCDIR}" + "GRASS_ETCDIR=${RUNTIME_GRASS_ETCDIR}" + "GRASS_FONTSDIR=${RUNTIME_GRASS_FONTSDIR}" + "GRASS_GRAPHICSDIR=${RUNTIME_GRASS_GRAPHICSDIR}" + "GRASS_GUIRESDIR=${RUNTIME_GRASS_GUIRESDIR}" + "GRASS_GUISCRIPTDIR=${RUNTIME_GRASS_GUISCRIPTDIR}" + "GRASS_GUIWXDIR=${GUI_WXPYTHON_DIR}" + "GRASS_LOCALEDIR=${RUNTIME_GRASS_LOCALEDIR}" + "GRASS_MKDOCSDIR=${RUNTIME_GRASS_MKDOCSDIR}" + "GRASS_SHAREDIR=${RUNTIME_GRASS_SHAREDIR}" "ARCH=${BUILD_ARCH}" "ARCH_DISTDIR=${RUN_GISBASE_NATIVE}" "LANGUAGE=C" "MODULE_TOPDIR=${MODULE_TOPDIR}" "HTMLDIR=${DOC_DIR}" "VERSION_NUMBER=\"${GRASS_VERSION_NUMBER}\"" @@ -299,14 +309,18 @@ endif() add_custom_target( r_colors_thumbnails ALL COMMAND ${CMAKE_COMMAND} -E make_directory - ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/colortables + ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/colortables COMMAND ${grass_env_command} ${PYTHON_EXECUTABLE} ${THUMBNAILS_PY} - ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/colortables - BYPRODUCTS ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/colortables + ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/colortables + BYPRODUCTS ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/colortables COMMENT "Creating thumbnails" DEPENDS ALL_MODULES) -install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/colortables - DESTINATION ${GRASS_INSTALL_DOCDIR}) +install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/colortables + DESTINATION ${GRASS_INSTALL_GRAPHICSDIR}) +if(WITH_FHS AND WITH_DOCS) + install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/colortables + DESTINATION ${GRASS_INSTALL_DOCDIR}) +endif() set(misc_files AUTHORS diff --git a/cmake/modules/GRASSInstallDirs.cmake b/cmake/modules/GRASSInstallDirs.cmake index f9f33ad178a..739790138a0 100644 --- a/cmake/modules/GRASSInstallDirs.cmake +++ b/cmake/modules/GRASSInstallDirs.cmake @@ -22,12 +22,14 @@ if(WITH_FHS) set(GRASS_INSTALL_DEVDOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME_LOWER}-dev-doc") set(GRASS_INSTALL_MANDIR "${CMAKE_INSTALL_MANDIR}") - set(GRASS_INSTALL_MKDOCSDIR - "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME_LOWER}-mkdocs") + set(GRASS_INSTALL_MKDOCSDIR "${GRASS_INSTALL_SHAREDIR}/mkdocs") set(GRASS_INSTALL_DEMODIR "${GRASS_INSTALL_SHAREDIR}/demolocation") set(GRASS_INSTALL_MISCDIR "${GRASS_INSTALL_SHAREDIR}") set(GRASS_INSTALL_MAKEFILEDIR "${GISBASE_DIR}/Make") set(GRASS_INSTALL_LOCALEDIR "${CMAKE_INSTALL_LOCALEDIR}") + set(GRASS_INSTALL_COLORSDIR "${GRASS_INSTALL_ETCDIR}/colors") + set(GRASS_INSTALL_GRAPHICSDIR "${GRASS_INSTALL_ETCDIR}/graphics") + set(GRASS_INSTALL_GRASS_GUIWXDIR "${GRASS_INSTALL_GUIDIR}/wxpython") else() message("Legacy file structure") set(GISBASE_DIR "${CMAKE_INSTALL_LIBDIR}/grass${GRASS_VERSION_MAJOR}${GRASS_VERSION_MINOR}") @@ -52,6 +54,9 @@ else() set(GRASS_INSTALL_MISCDIR "${GISBASE_DIR}") set(GRASS_INSTALL_MAKEFILEDIR "${GISBASE_DIR}/Make") set(GRASS_INSTALL_LOCALEDIR "${GISBASE_DIR}/locale") + set(GRASS_INSTALL_COLORSDIR "${GRASS_INSTALL_ETCDIR}/colors") + set(GRASS_INSTALL_GRAPHICSDIR "${GRASS_INSTALL_DOCDIR}") + set(GRASS_INSTALL_GRASS_GUIWXDIR "${GRASS_INSTALL_GUIDIR}/wxpython") endif() message(STATUS "GISBASE_DIR ${GISBASE_DIR}") @@ -76,10 +81,38 @@ message(STATUS "GRASS_INSTALL_DEMODIR ${GRASS_INSTALL_DEMODIR}") message(STATUS "GRASS_INSTALL_MISCDIR ${GRASS_INSTALL_MISCDIR}") message(STATUS "GRASS_INSTALL_MAKEFILEDIR ${GRASS_INSTALL_MAKEFILEDIR}") message(STATUS "GRASS_INSTALL_LOCALEDIR ${GRASS_INSTALL_LOCALEDIR}") +message(STATUS "GRASS_INSTALL_COLORSDIR ${GRASS_INSTALL_COLORSDIR}") +message(STATUS "GRASS_INSTALL_GRAPHICSDIR ${GRASS_INSTALL_GRAPHICSDIR}") +message(STATUS "GRASS_INSTALL_GRASS_GUIWXDIR ${GRASS_INSTALL_GRASS_GUIWXDIR}") set(OUTDIR "${CMAKE_BINARY_DIR}/output") set(GISBASE ${CMAKE_INSTALL_PREFIX}/${GISBASE_DIR}) + +set(GRASS_SHAREDIR "${GRASS_INSTALL_SHAREDIR}") +set(GRASS_LOCALEDIR "${GRASS_INSTALL_LOCALEDIR}") +set(GRASS_GUIRESDIR "${GRASS_INSTALL_GUIDIR}") +set(GRASS_GUISCRIPTDIR "${GRASS_INSTALL_GUISCRIPTDIR}") +set(GRASS_DOCDIR "${GRASS_INSTALL_DOCDIR}") +set(GRASS_MKDOCSDIR "${GRASS_INSTALL_MKDOCSDIR}") +set(GRASS_FONTSDIR "${GRASS_INSTALL_FONTSDIR}") +set(GRASS_COLORSDIR "${GRASS_INSTALL_COLORSDIR}") +set(GRASS_GRAPHICSDIR "${GRASS_INSTALL_GRAPHICSDIR}") +set(GRASS_ETCDIR "${GRASS_INSTALL_ETCDIR}") +set(GRASS_PYDIR "${GRASS_INSTALL_PYDIR}") +set(GRASS_GUIWXDIR "${GRASS_INSTALL_GRASS_GUIWXDIR}") + set(RUNTIME_GISBASE "${OUTDIR}/${GISBASE_DIR}") +set(RUNTIME_GRASS_SHAREDIR "${OUTDIR}/${GRASS_INSTALL_SHAREDIR}") +set(RUNTIME_GRASS_LOCALEDIR "${OUTDIR}/${GRASS_INSTALL_LOCALEDIR}") +set(RUNTIME_GRASS_GUIRESDIR "${OUTDIR}/${GRASS_INSTALL_GUIDIR}") +set(RUNTIME_GRASS_GUISCRIPTDIR "${OUTDIR}/${GRASS_INSTALL_GUISCRIPTDIR}") +set(RUNTIME_GRASS_DOCDIR "${OUTDIR}/${GRASS_INSTALL_DOCDIR}") +set(RUNTIME_GRASS_MKDOCSDIR "${OUTDIR}/${GRASS_INSTALL_MKDOCSDIR}") +set(RUNTIME_GRASS_FONTSDIR "${OUTDIR}/${GRASS_INSTALL_FONTSDIR}") +set(RUNTIME_GRASS_COLORSDIR "${OUTDIR}/${GRASS_INSTALL_COLORSDIR}") +set(RUNTIME_GRASS_GRAPHICSDIR "${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}") +set(RUNTIME_GRASS_ETCDIR "${OUTDIR}/${GRASS_INSTALL_ETCDIR}") + set(GISRC_NAME ".grassrc${GRASS_VERSION_MAJOR}${GRASS_VERSION_MINOR}") file(TO_NATIVE_PATH "${CMAKE_SOURCE_DIR}" MODULE_TOPDIR) diff --git a/cmake/modules/copy_python_files_in_subdir.cmake b/cmake/modules/copy_python_files_in_subdir.cmake index be477f6066c..26053c7936e 100644 --- a/cmake/modules/copy_python_files_in_subdir.cmake +++ b/cmake/modules/copy_python_files_in_subdir.cmake @@ -9,10 +9,15 @@ SPDX-License-Identifier: GPL-2.0-or-later #]] function(copy_python_files_in_subdir dir_name dst_prefix) - cmake_parse_arguments(G "PRE_BUILD;PRE_LINK;POST_BUILD" "TARGET" "" ${ARGN}) + cmake_parse_arguments(G "PRE_BUILD;PRE_LINK;POST_BUILD" "TARGET" "EXCLUDE" ${ARGN}) file(GLOB PY_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${dir_name}/*.py") + if(G_EXCLUDE) + list(TRANSFORM G_EXCLUDE APPEND "${CMAKE_CURRENT_SOURCE_DIR}/${dir_name}/") + list(REMOVE_ITEM PY_FILES ${G_EXCLUDE}) + endif() + if(DEFINED G_TARGET) if(${G_PRE_BUILD}) set(BUILD PRE_BUILD) diff --git a/display/CMakeLists.txt b/display/CMakeLists.txt index 9ddb3faa214..5be9432a33e 100644 --- a/display/CMakeLists.txt +++ b/display/CMakeLists.txt @@ -52,12 +52,16 @@ add_custom_command( TARGET d.barscale POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory - ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/barscales + ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/barscales COMMAND ${CMAKE_COMMAND} -E copy ${d_barscale_png} - ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/barscales - BYPRODUCTS ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/barscales) -install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/barscales - DESTINATION ${GRASS_INSTALL_DOCDIR}) + ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/barscales + BYPRODUCTS ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/barscales) +install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/barscales + DESTINATION ${GRASS_INSTALL_GRAPHICSDIR}) +if(WITH_FHS AND WITH_DOCS) + install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/barscales + DESTINATION ${GRASS_INSTALL_DOCDIR}) +endif() build_program_in_subdir(d.colorlist DEPENDS grass_gis grass_display grass_raster) @@ -108,13 +112,17 @@ build_program_in_subdir(d.linegraph DEPENDS grass_gis grass_display grass_symb build_program_in_subdir(d.northarrow DEPENDS grass_gis grass_display grass_symb ${LIBM}) if(WITH_DOCS) - file(MAKE_DIRECTORY ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/northarrows) + file(MAKE_DIRECTORY ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/northarrows) file(GLOB d_northarrow_png ${CMAKE_CURRENT_SOURCE_DIR}/d.northarrow/thumbnails/*.png) file(COPY ${d_northarrow_png} - DESTINATION ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/northarrows) - install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_DOCDIR}/northarrows - DESTINATION ${GRASS_INSTALL_DOCDIR}) + DESTINATION ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/northarrows) + install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/northarrows + DESTINATION ${GRASS_INSTALL_GRAPHICSDIR}) + if(WITH_FHS) + install(DIRECTORY ${OUTDIR}/${GRASS_INSTALL_GRAPHICSDIR}/northarrows + DESTINATION ${GRASS_INSTALL_DOCDIR}) + endif() endif() build_program_in_subdir(d.path DEPENDS grass_gis grass_display grass_vector) build_program_in_subdir(d.profile DEPENDS grass_gis grass_display grass_raster diff --git a/display/d.linegraph/main.c b/display/d.linegraph/main.c index 3aa493f78ac..654a080a9a2 100644 --- a/display/d.linegraph/main.c +++ b/display/d.linegraph/main.c @@ -89,7 +89,7 @@ static char *icon_files(void) list = NULL; len = 0; - snprintf(path, sizeof(path), "%s/etc/symbol", G_gisbase()); + snprintf(path, sizeof(path), "%s/etc/symbol", G_share_dir()); dir = opendir(path); if (!dir) @@ -102,7 +102,7 @@ static char *icon_files(void) if (d->d_name[0] == '.') continue; - snprintf(path_i, sizeof(path_i), "%s/etc/symbol/%s", G_gisbase(), + snprintf(path_i, sizeof(path_i), "%s/etc/symbol/%s", G_share_dir(), d->d_name); dir_i = opendir(path_i); diff --git a/display/d.mon/start.c b/display/d.mon/start.c index 2d741db0bf7..228bdc364c7 100644 --- a/display/d.mon/start.c +++ b/display/d.mon/start.c @@ -115,8 +115,12 @@ char *start_wx(const char *name, const char *element, int width, int height, mapfile = (char *)G_malloc(GPATH_MAX); mapfile[0] = '\0'; - snprintf(progname, sizeof(progname), "%s/gui/wxpython/mapdisp/main.py", - G_gisbase()); + const char *wxdir = getenv("GRASS_GUIWXDIR"); + if (!wxdir) + G_fatal_error(_("Incomplete GRASS session: Variable '%s' not set"), + "GRASS_GUIWXDIR"); + + snprintf(progname, sizeof(progname), "%s/mapdisp/main.py", wxdir); snprintf(str_width, sizeof(str_width), "%d", width); snprintf(str_height, sizeof(str_height), "%d", height); diff --git a/display/d.vect.thematic/main.c b/display/d.vect.thematic/main.c index 7fd51defe21..00e5934e101 100644 --- a/display/d.vect.thematic/main.c +++ b/display/d.vect.thematic/main.c @@ -645,7 +645,7 @@ static char *icon_files(void) list = NULL; len = 0; - snprintf(path, sizeof(path), "%s/etc/symbol", G_gisbase()); + snprintf(path, sizeof(path), "%s/etc/symbol", G_share_dir()); dir = opendir(path); if (!dir) @@ -658,7 +658,7 @@ static char *icon_files(void) if (d->d_name[0] == '.') continue; - snprintf(path_i, sizeof(path_i), "%s/etc/symbol/%s", G_gisbase(), + snprintf(path_i, sizeof(path_i), "%s/etc/symbol/%s", G_share_dir(), d->d_name); dir_i = opendir(path_i); diff --git a/display/d.vect/main.c b/display/d.vect/main.c index 265357a1ee7..4988b885425 100644 --- a/display/d.vect/main.c +++ b/display/d.vect/main.c @@ -531,7 +531,7 @@ char *icon_files(void) list = NULL; len = 0; - snprintf(path, sizeof(path), "%s/etc/symbol", G_gisbase()); + snprintf(path, sizeof(path), "%s/etc/symbol", G_share_dir()); dir = opendir(path); if (!dir) @@ -544,7 +544,7 @@ char *icon_files(void) if (d->d_name[0] == '.') continue; - snprintf(path_i, sizeof(path_i), "%s/etc/symbol/%s", G_gisbase(), + snprintf(path_i, sizeof(path_i), "%s/etc/symbol/%s", G_share_dir(), d->d_name); dir_i = opendir(path_i); diff --git a/doc/examples/gui/wxpython/frame.py b/doc/examples/gui/wxpython/frame.py index adba49b842d..36a28163ffc 100644 --- a/doc/examples/gui/wxpython/frame.py +++ b/doc/examples/gui/wxpython/frame.py @@ -22,7 +22,7 @@ # this enables to run application standalone (> python example/frame.py ) if __name__ == "__main__": - sys.path.append(os.path.join(os.environ["GISBASE"], "etc", "gui", "wxpython")) + sys.path.append(os.environ["GRASS_GUIWXDIR"]) # i18n is taken care of in the grass library code. # So we need to import it before any of the GUI code. diff --git a/doc/examples/gui/wxpython/g.gui.example.py b/doc/examples/gui/wxpython/g.gui.example.py old mode 100644 new mode 100755 index 9c04d659458..fb2e94f4c36 --- a/doc/examples/gui/wxpython/g.gui.example.py +++ b/doc/examples/gui/wxpython/g.gui.example.py @@ -38,7 +38,7 @@ import grass.script.core as gcore if __name__ == "__main__": - wxbase = os.path.join(os.getenv("GISBASE"), "etc", "gui", "wxpython") + wxbase = os.environ["GRASS_GUIWXDIR"] if wxbase not in sys.path: sys.path.append(wxbase) diff --git a/general/g.gui/main.c b/general/g.gui/main.c index 91e7de7e128..a34782d3faf 100644 --- a/general/g.gui/main.c +++ b/general/g.gui/main.c @@ -104,8 +104,12 @@ int main(int argc, char *argv[]) exit(EXIT_SUCCESS); } - snprintf(progname, sizeof(progname), "%s/gui/wxpython/wxgui.py", - G_gisbase()); + const char *wxdir = getenv("GRASS_GUIWXDIR"); + if (!wxdir) + G_fatal_error(_("Incomplete GRASS session: Variable '%s' not set"), + "GRASS_GUIWXDIR"); + + snprintf(progname, sizeof(progname), "%s/wxgui.py", wxdir); if (access(progname, F_OK) == -1) G_fatal_error(_("Your installation doesn't include GUI, exiting.")); diff --git a/general/g.mapset/main.c b/general/g.mapset/main.c index efef03d514b..9e214dea633 100644 --- a/general/g.mapset/main.c +++ b/general/g.mapset/main.c @@ -168,7 +168,7 @@ int main(int argc, char *argv[]) if (!gis_lock) G_fatal_error(_("Unable to read GIS_LOCK environment variable")); - G_asprintf(&lock_prog, "%s/etc/lock", G_gisbase()); + G_asprintf(&lock_prog, "%s/lock", G_etc_dir()); snprintf(path, sizeof(path), "%s/.gislock", mapset_new_path); G_debug(2, "%s", path); @@ -191,7 +191,7 @@ int main(int argc, char *argv[]) } /* Clean temporary directory */ - snprintf(path, sizeof(path), "%s/etc/clean_temp", G_gisbase()); + snprintf(path, sizeof(path), "%s/etc/clean_temp", G_share_dir()); G_verbose_message(_("Cleaning up temporary files...")); G_spawn(path, "clean_temp", NULL); diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 778e60703c1..a4ef2f2f832 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -215,8 +215,14 @@ int main(int argc, char *argv[]) if (opt.dialog->answer) { if (opt.mapset->answer) G_warning(_("Option <%s> ignored"), opt.mapset->key); - snprintf(path_buf, sizeof(path_buf), - "%s/gui/wxpython/modules/mapsets_picker.py", G_gisbase()); + + const char *wxdir = getenv("GRASS_GUIWXDIR"); + if (!wxdir) + G_fatal_error(_("Incomplete GRASS session: Variable '%s' not set"), + "GRASS_GUIWXDIR"); + + snprintf(path_buf, sizeof(path_buf), "%s/modules/mapsets_picker.py", + wxdir); G_spawn(getenv("GRASS_PYTHON"), "mapsets_picker.py", path_buf, NULL); exit(EXIT_SUCCESS); } diff --git a/general/g.mkfontcap/Makefile b/general/g.mkfontcap/Makefile index acf9cb184a3..78aa5240961 100644 --- a/general/g.mkfontcap/Makefile +++ b/general/g.mkfontcap/Makefile @@ -17,6 +17,7 @@ default: cmd $(CAPFILE) endif $(CAPFILE): $(BIN)/$(PGM)$(EXE) - GISRC=junk GISBASE=$(RUN_GISBASE) \ + GISRC=junk GISBASE=$(RUN_GISBASE) GRASS_SHAREDIR=$(RUN_GISBASE) \ + GRASS_LOCALEDIR=$(RUN_GISBASE)/locale GRASS_FONTSDIR=$(RUN_GISBASE)/fonts \ $(LD_LIBRARY_PATH_VAR)="$(ARCH_LIBDIR):$(BASE_LIBDIR):$($(LD_LIBRARY_PATH_VAR))" \ $< -s > $@ diff --git a/general/g.mkfontcap/main.c b/general/g.mkfontcap/main.c index 0280e966103..be1a674dc93 100644 --- a/general/g.mkfontcap/main.c +++ b/general/g.mkfontcap/main.c @@ -86,13 +86,13 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); if (!tostdout->answer) { - const char *gisbase = G_gisbase(); + const char *share_dir = G_share_dir(); const char *alt_file = getenv("GRASS_FONT_CAP"); if (alt_file) fontcapfile = G_store(alt_file); else - G_asprintf(&fontcapfile, "%s/etc/fontcap", gisbase); + G_asprintf(&fontcapfile, "%s/etc/fontcap", share_dir); if (!access(fontcapfile, F_OK)) { /* File exists? */ if (!G_get_overwrite()) diff --git a/general/g.mkfontcap/stroke_fonts.c b/general/g.mkfontcap/stroke_fonts.c index d94b0f441c0..afbfa87d135 100644 --- a/general/g.mkfontcap/stroke_fonts.c +++ b/general/g.mkfontcap/stroke_fonts.c @@ -48,12 +48,11 @@ static const char *get_desc(const char *); void find_stroke_fonts(void) { - char *dirpath, *fonttable; + char *fonttable; char **dirlisting; int numfiles, i; - G_asprintf(&dirpath, "%s/fonts", G_gisbase()); - + const char *dirpath = G_fonts_dir(); dirlisting = G_ls2(dirpath, &numfiles); G_asprintf(&fonttable, "%s/fonts.table", dirpath); diff --git a/general/g.setproj/get_stp.c b/general/g.setproj/get_stp.c index 3969a735f38..54b51a4f0f3 100644 --- a/general/g.setproj/get_stp.c +++ b/general/g.setproj/get_stp.c @@ -51,7 +51,7 @@ int get_stp_code(int code, char *string, char *paramfile) int gotit = 0, stp; FILE *fp; - snprintf(nad27, sizeof(nad27), "%s%s", G_gisbase(), paramfile); + snprintf(nad27, sizeof(nad27), "%s%s", G_share_dir(), paramfile); fp = fopen(nad27, "r"); if (fp == NULL) { snprintf(buff, sizeof(buff), "Can not open NAD27 file %s", nad27); @@ -84,7 +84,8 @@ int get_stp_num(void) int record, icode, reccnt = 0, special_case; char STabbr[50], COname[50]; - snprintf(FIPSfile, sizeof(FIPSfile), "%s/etc/proj/FIPS.code", G_gisbase()); + snprintf(FIPSfile, sizeof(FIPSfile), "%s/etc/proj/FIPS.code", + G_share_dir()); for (;;) { diff --git a/general/g.setproj/proj.c b/general/g.setproj/proj.c index eb6de8a7bd7..7be8946758a 100644 --- a/general/g.setproj/proj.c +++ b/general/g.setproj/proj.c @@ -13,7 +13,7 @@ struct proj_unit *get_proj_unit(const char *arg) struct proj_unit *unit; FILE *fp; - snprintf(buf, sizeof(buf), "%s/etc/proj/units.table", G_gisbase()); + snprintf(buf, sizeof(buf), "%s/etc/proj/units.table", G_share_dir()); fp = fopen(buf, "r"); if (!fp) @@ -51,7 +51,7 @@ struct proj_desc *get_proj_desc(const char *arg) struct proj_desc *res; FILE *fp; - snprintf(buf, sizeof(buf), "%s/etc/proj/desc.table", G_gisbase()); + snprintf(buf, sizeof(buf), "%s/etc/proj/desc.table", G_share_dir()); fp = fopen(buf, "r"); if (!fp) @@ -92,7 +92,7 @@ struct proj_parm *get_proj_parms(const char *arg) int done; FILE *fp; - snprintf(buf, sizeof(buf), "%s/etc/proj/parms.table", G_gisbase()); + snprintf(buf, sizeof(buf), "%s/etc/proj/parms.table", G_share_dir()); fp = fopen(buf, "r"); if (!fp) diff --git a/gui/wxpython/core/globalvar.py b/gui/wxpython/core/globalvar.py index a3c8b50de79..7e3cbd1cbec 100644 --- a/gui/wxpython/core/globalvar.py +++ b/gui/wxpython/core/globalvar.py @@ -26,11 +26,11 @@ from pathlib import Path # path to python scripts -ETCDIR = os.path.join(os.getenv("GISBASE"), "etc") -GUIDIR = os.path.join(os.getenv("GISBASE"), "gui") -WXGUIDIR = os.path.join(GUIDIR, "wxpython") -ICONDIR = os.path.join(GUIDIR, "icons") -IMGDIR = os.path.join(GUIDIR, "images") +PYDIR = os.getenv("GRASS_PYDIR") +ETCDIR = os.path.join(os.getenv("GRASS_SHAREDIR"), "etc") +WXGUIDIR = os.getenv("GRASS_GUIWXDIR") +ICONDIR = os.path.join(os.getenv("GRASS_GUIRESDIR"), "icons") +IMGDIR = os.path.join(os.getenv("GRASS_GUIRESDIR"), "images") SYMBDIR = os.path.join(IMGDIR, "symbols") WXPY3_MIN_VERSION = [4, 0, 0, 0] @@ -249,7 +249,7 @@ def UpdateGRASSAddOnCommands(eList=None): gtk3 = "gtk3" in wx.PlatformInfo # Add GUIDIR/scripts into path -os.environ["PATH"] = os.path.join(GUIDIR, "scripts") + os.pathsep + os.environ["PATH"] +os.environ["PATH"] = os.environ["GRASS_GUISCRIPTDIR"] + os.pathsep + os.environ["PATH"] ignoredCmdPattern = ( r"^d\..*|^r[3]?\.mapcalc$|^i.group$|^r.import$|" diff --git a/gui/wxpython/core/settings.py b/gui/wxpython/core/settings.py index e0758a482d6..10a126d10ba 100644 --- a/gui/wxpython/core/settings.py +++ b/gui/wxpython/core/settings.py @@ -105,7 +105,7 @@ def __init__(self): def _generateLocale(self): """Generate locales""" try: - locale_path = Path(os.environ["GISBASE"]) / "locale" + locale_path = Path(os.environ["GRASS_LOCALEDIR"]) self.locs = [p.name for p in locale_path.iterdir() if p.is_dir()] self.locs.append("en") # GRASS doesn't ship EN po files self.locs.sort() diff --git a/gui/wxpython/core/toolboxes.py b/gui/wxpython/core/toolboxes.py index 0bfac9d6b9f..2f9ec1b4f3f 100644 --- a/gui/wxpython/core/toolboxes.py +++ b/gui/wxpython/core/toolboxes.py @@ -31,7 +31,7 @@ # if this will become part of grass Python library or module, this should be # parametrized, so we will get rid of the definition here # (GUI will use its definition and build also its own) -WXGUIDIR = os.path.join(os.getenv("GISBASE"), "gui", "wxpython") +WXGUIDIR = os.environ["GRASS_GUIWXDIR"] # this could be placed to functions diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index 3e545e86245..f75217bb6f1 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -1727,7 +1727,7 @@ class ColorTablesComboBox(PictureComboBox): def _getPath(self, name): return os.path.join( - os.getenv("GISBASE"), "docs", "html", "colortables", "%s.png" % name + os.getenv("GRASS_GRAPHICSDIR"), "colortables", "%s.png" % name ) @@ -1735,9 +1735,7 @@ class BarscalesComboBox(PictureComboBox): """ComboBox with barscales for d.barscale.""" def _getPath(self, name): - return os.path.join( - os.getenv("GISBASE"), "docs", "html", "barscales", name + ".png" - ) + return os.path.join(os.getenv("GRASS_GRAPHICSDIR"), "barscales", name + ".png") class NArrowsComboBox(PictureComboBox): @@ -1745,7 +1743,7 @@ class NArrowsComboBox(PictureComboBox): def _getPath(self, name): return os.path.join( - os.getenv("GISBASE"), "docs", "html", "northarrows", "%s.png" % name + os.getenv("GRASS_GRAPHICSDIR"), "northarrows", "%s.png" % name ) diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index e2b3da9e60d..c9952ed6160 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -88,11 +88,9 @@ def __init__(self, parent=None, id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE): # image try: if os.getenv("ISISROOT"): - name = os.path.join( - globalvar.GUIDIR, "images", "startup_banner_isis.png" - ) + name = os.path.join(globalvar.IMGDIR, "startup_banner_isis.png") else: - name = os.path.join(globalvar.GUIDIR, "images", "startup_banner.png") + name = os.path.join(globalvar.IMGDIR, "startup_banner.png") self.hbitmap = wx.StaticBitmap( self.panel, wx.ID_ANY, wx.Bitmap(name=name, type=wx.BITMAP_TYPE_PNG) ) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 9524c3a8b5d..3f64806f9cd 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -35,8 +35,8 @@ except ImportError: import wx.lib.flatnotebook as FN -if os.path.join(globalvar.ETCDIR, "python") not in sys.path: - sys.path.append(os.path.join(globalvar.ETCDIR, "python")) +if globalvar.PYDIR not in sys.path: + sys.path.append(globalvar.PYDIR) from grass.script import core as grass from grass.script.utils import decode diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index dd7dbe4cf69..d4d5891e619 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -41,8 +41,8 @@ except ImportError: import wx.lib.flatnotebook as FN -if os.path.join(globalvar.ETCDIR, "python") not in sys.path: - sys.path.append(os.path.join(globalvar.ETCDIR, "python")) +if globalvar.PYDIR not in sys.path: + sys.path.append(globalvar.PYDIR) from grass.script import core as grass from grass.script.utils import decode diff --git a/gui/wxpython/psmap/dialogs.py b/gui/wxpython/psmap/dialogs.py index 2561e3c388e..fc0cec0698d 100644 --- a/gui/wxpython/psmap/dialogs.py +++ b/gui/wxpython/psmap/dialogs.py @@ -2203,13 +2203,13 @@ def __init__(self, parent, id, vectors, tmpSettings): self.currLayer = self.vPropertiesDict["layer"] # path to symbols, patterns - gisbase = os.getenv("GISBASE") - self.symbolPath = os.path.join(gisbase, "etc", "symbol") + g_share_dir = os.getenv("GRASS_SHAREDIR") + self.symbolPath = os.path.join(g_share_dir, "etc", "symbol") self.symbols = [] for dir in Path(self.symbolPath).iterdir(): for symbol in Path(self.symbolPath).joinpath(dir.name).iterdir(): self.symbols.append(os.path.join(dir.name, symbol.name)) - self.patternPath = os.path.join(gisbase, "etc", "paint", "patterns") + self.patternPath = os.path.join(g_share_dir, "etc", "paint", "patterns") # notebook notebook = Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT) @@ -6193,8 +6193,8 @@ def _newObject(self): return NorthArrow(self.id, self.instruction, env=self.env) def _getImageDirectory(self): - gisbase = os.getenv("GISBASE") - return os.path.join(gisbase, "etc", "paint", "decorations") + g_share_dir = os.getenv("GRASS_SHAREDIR") + return os.path.join(g_share_dir, "etc", "paint", "decorations") def _addConvergence(self, panel, gridBagSizer): convergence = Button(parent=panel, id=wx.ID_ANY, label=_("Compute convergence")) diff --git a/include/Make/Install.make b/include/Make/Install.make index 799a695e80d..c9e757e634d 100644 --- a/include/Make/Install.make +++ b/include/Make/Install.make @@ -124,6 +124,12 @@ $(DESTDIR)$(INST_DIR) $(DESTDIR)$(UNIX_BIN): $(STARTUP): $(ARCH_DISTDIR)/$(GRASS_NAME).tmp sed -e 's#'@GISBASE_INSTALL_PATH@'#'$(INST_DIR)'#g' \ -e 's#'@LD_LIBRARY_PATH_VAR@'#'$(LD_LIBRARY_PATH_VAR)'#g' \ + -e 's#@GRASS_SHAREDIR@#$(INST_DIR)#' \ + -e 's#@GRASS_LOCALE@#$(INST_DIR)/locale#' \ + -e 's#@GRASS_PYDIR@#$(INST_DIR)/etc/python#' \ + -e 's#@GRASS_GUIWXDIR@#$(INST_DIR)/gui/wxpython#' \ + -e 's#@GRASS_GUISCRIPTDIR@#$(INST_DIR)/gui/scripts#' \ + -e 's#@GRASS_GUIRESDIR@#$(INST_DIR)/gui#' \ -e 's#'@CONFIG_PROJSHARE@'#'$(PROJSHARE)'#g' \ $< > $@ -$(CHMOD) a+x $@ diff --git a/include/Make/Rules.make b/include/Make/Rules.make index 9e765fab7a4..0cc10177c51 100644 --- a/include/Make/Rules.make +++ b/include/Make/Rules.make @@ -45,6 +45,16 @@ GRASS_PYTHONPATH := $(call mkpath,$(GISBASE)/etc/python,$(GRASS_PYTHONPATH)) run_grass = \ GISRC=$(RUN_GISRC) \ GISBASE=$(RUN_GISBASE) \ + GRASS_SHAREDIR=$(RUN_GISBASE) \ + GRASS_LOCALEDIR=$(RUN_GISBASE)/locale \ + GRASS_GUIWXDIR=$(RUN_GISBASE)/gui/wxpython \ + GRASS_GUIRESDIR=$(RUN_GISBASE)/gui \ + GRASS_GUISCRIPTDIR=$(RUN_GISBASE)/gui/scripts \ + GRASS_MKDOCSDIR=$(RUN_GISBASE)/docs/mkdocs \ + GRASS_COLORSDIR=$(RUN_GISBASE)/etc/colors \ + GRASS_FONTSDIR=$(RUN_GISBASE)/fonts \ + GRASS_GRAPHICSDIR=$(RUN_GISBASE)/docs/html \ + GRASS_ETCDIR=$(RUN_GISBASE)/etc \ PATH="$(ARCH_DISTDIR)/bin:$(GISBASE)/bin:$(GISBASE)/scripts:$$PATH" \ PYTHONPATH="$(GRASS_PYTHONPATH)" \ $(LD_LIBRARY_PATH_VAR)="$(BIN):$(GISBASE)/bin:$(GISBASE)/scripts:$(ARCH_LIBDIR):$(BASE_LIBDIR):$($(LD_LIBRARY_PATH_VAR))" \ diff --git a/include/grass/defs/gis.h b/include/grass/defs/gis.h index 8bacb260cc2..8f1af5e47e8 100644 --- a/include/grass/defs/gis.h +++ b/include/grass/defs/gis.h @@ -394,6 +394,13 @@ void G__gisinit(const char *, const char *); void G__no_gisinit(const char *); void G_init_all(void); +/* grass_install_dirs.c */ +const char *G_locale_dir(void); +const char *G_share_dir(void); +const char *G_fonts_dir(void); +const char *G_colors_dir(void); +const char *G_etc_dir(void); + /* handler.c */ void G_add_error_handler(void (*)(void *), void *); void G_remove_error_handler(void (*)(void *), void *); diff --git a/lib/driver/font2.c b/lib/driver/font2.c index eaa91e069d6..4b1091ff13a 100644 --- a/lib/driver/font2.c +++ b/lib/driver/font2.c @@ -128,7 +128,7 @@ static void load_glyphs(void) for (i = 1; i <= 4; i++) { char buf[GPATH_MAX]; - snprintf(buf, sizeof(buf), "%s/fonts/hersh.oc%d", G_gisbase(), i); + snprintf(buf, sizeof(buf), "%s/fonts/hersh.oc%d", G_share_dir(), i); read_hersh(buf); } } @@ -141,7 +141,7 @@ static void read_fontmap(const char *name) num_chars = 0; memset(fontmap, 0, sizeof(fontmap)); - snprintf(buf, sizeof(buf), "%s/fonts/%s.hmp", G_gisbase(), name); + snprintf(buf, sizeof(buf), "%s/fonts/%s.hmp", G_share_dir(), name); fp = fopen(buf, "r"); if (!fp) { diff --git a/lib/driver/parse_ftcap.c b/lib/driver/parse_ftcap.c index e8be0572c25..4c03d83fba2 100644 --- a/lib/driver/parse_ftcap.c +++ b/lib/driver/parse_ftcap.c @@ -86,7 +86,7 @@ struct GFONT_CAP *parse_fontcap(void) capfile); } if (fp == NULL) { - snprintf(file, sizeof(file), "%s/etc/fontcap", G_gisbase()); + snprintf(file, sizeof(file), "%s/fontcap", G_etc_dir()); if ((fp = fopen(file, "r")) == NULL) G_warning(_("%s: No font definition file"), file); } diff --git a/lib/gis/color_rules.c b/lib/gis/color_rules.c index bb3ace277f8..8c998b223df 100644 --- a/lib/gis/color_rules.c +++ b/lib/gis/color_rules.c @@ -268,7 +268,7 @@ struct colorinfo *get_colorinfo(int *nrules) char **cnames; /* load color rules */ - snprintf(path, GPATH_MAX, "%s/etc/colors", G_gisbase()); + snprintf(path, GPATH_MAX, "%s", G_colors_dir()); *nrules = 0; cnames = G_ls2(path, nrules); @@ -284,8 +284,7 @@ struct colorinfo *get_colorinfo(int *nrules) colorinfo[i].desc = NULL; /* open color rule file */ - snprintf(path, GPATH_MAX, "%s/etc/colors/%s", G_gisbase(), - colorinfo[i].name); + snprintf(path, GPATH_MAX, "%s/%s", G_colors_dir(), colorinfo[i].name); fp = fopen(path, "r"); if (!fp) G_fatal_error(_("Unable to open color rule")); @@ -361,7 +360,7 @@ struct colorinfo *get_colorinfo(int *nrules) qsort(colorinfo, *nrules, sizeof(struct colorinfo), cmp_clrname); /* load color descriptions */ - snprintf(path, GPATH_MAX, "%s/etc/colors.desc", G_gisbase()); + snprintf(path, GPATH_MAX, "%s/colors.desc", G_etc_dir()); fp = fopen(path, "r"); if (!fp) G_fatal_error(_("Unable to open color descriptions")); diff --git a/lib/gis/datum.c b/lib/gis/datum.c index 8931dd328de..aeaed3c1246 100644 --- a/lib/gis/datum.c +++ b/lib/gis/datum.c @@ -148,7 +148,7 @@ void G_read_datum_table(void) if (G_is_initialized(&table.initialized)) return; - snprintf(file, sizeof(file), "%s%s", G_gisbase(), DATUMTABLE); + snprintf(file, sizeof(file), "%s%s", G_share_dir(), DATUMTABLE); fd = fopen(file, "r"); if (!fd) { diff --git a/lib/gis/find_etc.c b/lib/gis/find_etc.c index 59e8579689e..eed15c21c62 100644 --- a/lib/gis/find_etc.c +++ b/lib/gis/find_etc.c @@ -40,7 +40,7 @@ static char *G__find_etc(const char *name) /* * check application etc dir */ - snprintf(path, sizeof(path), "%s/etc/%s", G_gisbase(), name); + snprintf(path, sizeof(path), "%s/etc/%s", G_share_dir(), name); if (access(path, 0) == 0) return G_store(path); diff --git a/lib/gis/get_ellipse.c b/lib/gis/get_ellipse.c index 2a208c47bed..802200d6406 100644 --- a/lib/gis/get_ellipse.c +++ b/lib/gis/get_ellipse.c @@ -255,7 +255,7 @@ int G_read_ellipsoid_table(int fatal) if (G_is_initialized(&table.initialized)) return 1; - snprintf(file, sizeof(file), "%s/etc/proj/ellipse.table", G_gisbase()); + snprintf(file, sizeof(file), "%s/etc/proj/ellipse.table", G_share_dir()); fd = fopen(file, "r"); if (fd == NULL) { diff --git a/lib/gis/grass_install_dirs.c b/lib/gis/grass_install_dirs.c new file mode 100644 index 00000000000..468def9b5a6 --- /dev/null +++ b/lib/gis/grass_install_dirs.c @@ -0,0 +1,53 @@ +/*! + \file lib/gis/grass_install_dirs.c + + \brief GIS Library - Handles program initialization. + + \author Nicklas Larsson + + (c) 2025 by the GRASS Development Team + + SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include + +#include +#include + +static const char *get_g_env(const char *); + +const char *G_share_dir(void) +{ + return get_g_env("GRASS_SHAREDIR"); +} + +const char *G_locale_dir(void) +{ + return get_g_env("GRASS_LOCALEDIR"); +} + +const char *G_fonts_dir(void) +{ + return get_g_env("GRASS_FONTSDIR"); +} + +const char *G_colors_dir(void) +{ + return get_g_env("GRASS_COLORSDIR"); +} + +const char *G_etc_dir(void) +{ + return get_g_env("GRASS_ETCDIR"); +} + +static const char *get_g_env(const char *env_var) +{ + const char *value = getenv(env_var); + if (value) + return value; + + G_fatal_error(_("Incomplete GRASS session: Variable '%s' not set"), + env_var); +} diff --git a/lib/gis/is.c b/lib/gis/is.c index 3882f7d25e5..73ff6fc8274 100644 --- a/lib/gis/is.c +++ b/lib/gis/is.c @@ -49,7 +49,7 @@ static int test_path_file(const char *path, const char *file) int G_is_gisbase(const char *path) { - return test_path_file(path, "etc/element_list"); + return test_path_file(path, "etc/echo"); } /** diff --git a/lib/gis/locale.c b/lib/gis/locale.c index de0784f234c..3d45a6e74eb 100644 --- a/lib/gis/locale.c +++ b/lib/gis/locale.c @@ -39,14 +39,9 @@ void G_init_locale(void) #ifdef LC_MESSAGES setlocale(LC_MESSAGES, ""); #endif - const char *gisbase = getenv("GISBASE"); - - if (gisbase && *gisbase) { - char localedir[GPATH_MAX]; - - strcpy(localedir, gisbase); - strcat(localedir, "/locale"); + const char *localedir = G_locale_dir(); + if (localedir && *localedir) { bindtextdomain("grasslibs", localedir); bindtextdomain("grassmods", localedir); } diff --git a/lib/gis/parser.c b/lib/gis/parser.c index a7415dfc4c8..df556e272b0 100644 --- a/lib/gis/parser.c +++ b/lib/gis/parser.c @@ -988,8 +988,12 @@ int module_gui_wx(void) if (!st->pgm_path) G_fatal_error(_("Unable to determine program name")); - snprintf(script, GPATH_MAX, "%s/gui/wxpython/gui_core/forms.py", - getenv("GISBASE")); + const char *wxdir = getenv("GRASS_GUIWXDIR"); + if (!wxdir) + G_fatal_error(_("Incomplete GRASS session: Variable '%s' not set"), + "GRASS_GUIWXDIR"); + + snprintf(script, GPATH_MAX, "%s/gui_core/forms.py", wxdir); if (access(script, F_OK) != -1) G_spawn(getenv("GRASS_PYTHON"), getenv("GRASS_PYTHON"), script, G_recreate_command_original_path(), NULL); @@ -1816,7 +1820,7 @@ const char *get_renamed_option(const char *key) /* read renamed options from file (renamed_options) */ char path[GPATH_MAX]; - snprintf(path, GPATH_MAX, "%s/etc/renamed_options", G_gisbase()); + snprintf(path, GPATH_MAX, "%s/etc/renamed_options", G_share_dir()); st->renamed_options = G_read_key_value_file(path); } diff --git a/lib/init/CMakeLists.txt b/lib/init/CMakeLists.txt index 89509db5c69..1071c67fba7 100644 --- a/lib/init/CMakeLists.txt +++ b/lib/init/CMakeLists.txt @@ -60,11 +60,14 @@ endif() # configure and install grass.py set(GISBASE_INSTALL_PATH ${RUNTIME_GISBASE}) +set(GRASS_PREFIX ${OUTDIR}) configure_file(grass.py ${OUTDIR}/${CMAKE_INSTALL_BINDIR}/${START_UP} @ONLY) set(GISBASE_INSTALL_PATH ${GISBASE}) +set(GRASS_PREFIX ${CMAKE_INSTALL_PREFIX}) configure_file(grass.py ${CMAKE_CURRENT_BINARY_DIR}/${START_UP} @ONLY) unset(GISBASE_INSTALL_PATH) +unset(GRASS_PREFIX) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${START_UP} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/lib/init/Makefile b/lib/init/Makefile index 99366b060a9..b6f25204b04 100644 --- a/lib/init/Makefile +++ b/lib/init/Makefile @@ -69,7 +69,6 @@ $(ARCH_BINDIR)/$(START_UP): grass.py endif rm -f $@ sed \ - -e 's#@GISBASE_INSTALL_PATH@#$(RUN_GISBASE)#' \ -e 's#@GRASS_VERSION_NUMBER@#$(GRASS_VERSION_NUMBER)#' \ -e 's#@GRASS_VERSION_MAJOR@#$(GRASS_VERSION_MAJOR)#' \ -e 's#@GRASS_VERSION_MINOR@#$(GRASS_VERSION_MINOR)#' \ @@ -77,6 +76,8 @@ endif -e 's#@LD_LIBRARY_PATH_VAR@#$(LD_LIBRARY_PATH_VAR)#' \ -e 's#@START_UP@#$(START_UP)#' \ -e 's#@CONFIG_PROJSHARE@#$(PROJSHARE)#' \ + -e 's#@GRASS_PREFIX@#$(RUN_GISBASE)#' \ + -e 's#@GRASS_PYDIR@#etc/python#' \ $< > $@ chmod +x $@ @@ -91,6 +92,8 @@ $(ARCH_DISTDIR)/$(START_UP).tmp: grass.py -e 's#@GRASS_CONFIG_DIR@#$(GRASS_CONFIG_DIR)#' \ -e 's#@LD_LIBRARY_PATH_VAR@#$(LD_LIBRARY_PATH_VAR)#' \ -e 's#@CONFIG_PROJSHARE@#$(PROJSHARE)#' \ + -e 's#@GRASS_PREFIX@#$(RUN_GISBASE)#' \ + -e 's#@GRASS_PYDIR@#etc/python#' \ $< > $@ $(ETC)/echo$(EXE) $(ETC)/run$(EXE): $(ETC)/%$(EXE): $(OBJDIR)/%.o diff --git a/lib/init/grass.py b/lib/init/grass.py index 2e6d955cb06..dc35c4af690 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -71,6 +71,8 @@ # for wxpath _WXPYTHON_BASE = None +GISBASE = None + try: # Python >= 3.11 ENCODING = locale.getencoding() @@ -81,25 +83,7 @@ print("Default locale not found, using UTF-8") # intentionally not translatable # The "@...@" variables are being substituted during build process -# -# TODO: should GISBASE be renamed to something like GRASS_PATH? -# GISBASE marks complete runtime, so no need to get it here when -# setting it up, possible scenario: existing runtime and starting -# GRASS in that, we want to overwrite the settings, not to take it -# possibly same for GRASS_PROJSHARE and others but maybe not -# -# We need to simultaneously make sure that: -# - we get GISBASE from os.environ if it is defined (doesn't this mean that we are -# already inside a GRASS session? If we are, why do we need to run this script -# again???). -# - GISBASE exists as an ENV variable -# -# pmav99: Ugly as hell, but that's what the code before the refactoring was doing. -if "GISBASE" in os.environ and len(os.getenv("GISBASE")) > 0: - GISBASE = os.path.normpath(os.environ["GISBASE"]) -else: - GISBASE = os.path.normpath("@GISBASE_INSTALL_PATH@") - os.environ["GISBASE"] = GISBASE + CMD_NAME = "@START_UP@" GRASS_VERSION = "@GRASS_VERSION_NUMBER@" GRASS_VERSION_MAJOR = "@GRASS_VERSION_MAJOR@" @@ -1184,7 +1168,7 @@ def set_language(grass_config_dir: StrPath) -> None: os.environ["LC_MESSAGES"] = "C" os.environ["LC_NUMERIC"] = "C" os.environ["LC_TIME"] = "C" - gettext.install("grasslibs", gpath("locale")) + gettext.install("grasslibs", os.environ["GRASS_LOCALEDIR"]) sys.stderr.write( "All attempts to enable English language have" " failed. GRASS running with C locale.\n" @@ -1265,7 +1249,7 @@ def set_language(grass_config_dir: StrPath) -> None: del os.environ["LC_ALL"] # Remove LC_ALL to not override LC_NUMERIC # From now on enforce the new language - gettext.install("grasslibs", gpath("locale")) + gettext.install("grasslibs", os.environ["GRASS_LOCALEDIR"]) # TODO: the gisrcrc here does not make sense, remove it from load_gisrc @@ -2103,9 +2087,16 @@ def validate_cmdline(params: Parameters) -> None: def find_grass_python_package() -> None: """Find path to grass package and add it to path""" - if os.path.exists(gpath("etc", "python")): - path_to_package = gpath("etc", "python") - sys.path.append(path_to_package) + GRASS_PREFIX = "@GRASS_PREFIX@" + + if "GRASS_PYDIR" in os.environ and len(os.getenv("GRASS_PYDIR")) > 0: + GRASS_PYDIR = os.path.normpath(os.environ["GRASS_PYDIR"]) + else: + GRASS_PYDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_PYDIR@")) + os.environ["GRASS_PYDIR"] = GRASS_PYDIR + + if os.path.exists(GRASS_PYDIR): + sys.path.append(GRASS_PYDIR) # now we can import stuff from grass package else: # Not translatable because we don't have translations loaded. @@ -2115,6 +2106,12 @@ def find_grass_python_package() -> None: ) raise RuntimeError(msg) + from grass.app import resource_paths + + resource_paths.set_resource_paths() # noqa: F821 + global GISBASE + GISBASE = resource_paths.GISBASE + def main() -> None: """The main function which does the whole setup and run procedure diff --git a/lib/manage/read_list.c b/lib/manage/read_list.c index 3c9d5fece4d..793b55a0ab8 100644 --- a/lib/manage/read_list.c +++ b/lib/manage/read_list.c @@ -66,7 +66,7 @@ int M_read_list(int check_if_empty, int *num) if (env) strcpy(element_list, env); else - snprintf(element_list, GPATH_MAX, "%s/etc/element_list", G_gisbase()); + snprintf(element_list, GPATH_MAX, "%s/element_list", G_etc_dir()); fd = fopen(element_list, "r"); if (!fd) diff --git a/lib/proj/convert.c b/lib/proj/convert.c index 43edf512c10..d2950351e03 100644 --- a/lib/proj/convert.c +++ b/lib/proj/convert.c @@ -501,7 +501,7 @@ int GPJ_osr_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo, * system */ snprintf(path, sizeof(path), "%s/etc/proj/projections", - G_gisbase()); + G_share_dir()); if (G_lookup_key_value_from_file(path, pszProj, name, sizeof(name)) > 0) G_set_key_value("name", name, *projinfo); @@ -637,7 +637,7 @@ int GPJ_osr_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo, /* use name of the projection as name for the coordinate system */ snprintf(path, sizeof(path), "%s/etc/proj/projections", - G_gisbase()); + G_share_dir()); if (G_lookup_key_value_from_file(path, pszProj, name, sizeof(name)) > 0) G_set_key_value("name", name, *projinfo); @@ -1011,13 +1011,13 @@ int GPJ_wkt_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo, const char *GPJ_set_csv_loc(const char *name) { - const char *gisbase = G_gisbase(); + const char *g_share_dir = G_share_dir(); static char *buf = NULL; if (buf != NULL) G_free(buf); - G_asprintf(&buf, "%s%s/%s", gisbase, CSVDIR, name); + G_asprintf(&buf, "%s%s/%s", g_share_dir, CSVDIR, name); return buf; } diff --git a/lib/proj/datum.c b/lib/proj/datum.c index 1680b554f22..3bd9f5c5466 100644 --- a/lib/proj/datum.c +++ b/lib/proj/datum.c @@ -270,7 +270,7 @@ GPJ_get_datum_transform_by_name(const char *inputname) /* Now check for additional parameters in datumtransform.table */ - snprintf(file, sizeof(file), "%s%s", G_gisbase(), DATUMTRANSFORMTABLE); + snprintf(file, sizeof(file), "%s%s", G_share_dir(), DATUMTRANSFORMTABLE); fd = fopen(file, "r"); if (!fd) { @@ -347,7 +347,7 @@ struct datum_list *read_datum_table(void) int line; struct datum_list *current = NULL, *outputlist = NULL; - snprintf(file, sizeof(file), "%s%s", G_gisbase(), DATUMTABLE); + snprintf(file, sizeof(file), "%s%s", G_share_dir(), DATUMTABLE); fd = fopen(file, "r"); if (!fd) { diff --git a/lib/proj/ellipse.c b/lib/proj/ellipse.c index ff26e096902..9f297ef519b 100644 --- a/lib/proj/ellipse.c +++ b/lib/proj/ellipse.c @@ -233,7 +233,7 @@ struct ellps_list *read_ellipsoid_table(int fatal) struct ellps_list *current = NULL, *outputlist = NULL; double a, e2, rf; - snprintf(file, sizeof(file), "%s%s", G_gisbase(), ELLIPSOIDTABLE); + snprintf(file, sizeof(file), "%s%s", G_share_dir(), ELLIPSOIDTABLE); fd = fopen(file, "r"); if (!fd) { diff --git a/lib/psdriver/graph_set.c b/lib/psdriver/graph_set.c index fad5d70d1bc..600ab23f850 100644 --- a/lib/psdriver/graph_set.c +++ b/lib/psdriver/graph_set.c @@ -57,7 +57,7 @@ static void write_prolog(void) strftime(date_str, sizeof(date_str), DATE_FORMAT, tm); snprintf(prolog_file, sizeof(prolog_file), "%s/etc/psdriver.ps", - G_gisbase()); + G_share_dir()); prolog_fp = fopen(prolog_file, "r"); if (!prolog_fp) diff --git a/lib/raster/color_rules.c b/lib/raster/color_rules.c index 1d9ddd6f1eb..910bc050103 100644 --- a/lib/raster/color_rules.c +++ b/lib/raster/color_rules.c @@ -318,7 +318,7 @@ static void load_rules_name(struct Colors *colors, const char *name, DCELL min, { char path[GPATH_MAX]; - snprintf(path, sizeof(path), "%s/etc/colors/%s", G_gisbase(), name); + snprintf(path, sizeof(path), "%s/%s", G_colors_dir(), name); if (!load_rules_file(colors, path, min, max)) G_fatal_error(_("Unable to load color rules <%s>"), name); diff --git a/lib/symbol/read.c b/lib/symbol/read.c index 5aacb78b32f..c1d7db06b46 100644 --- a/lib/symbol/read.c +++ b/lib/symbol/read.c @@ -273,7 +273,7 @@ SYMBOL *S_read(const char *sname) fp = G_fopen_old(buf, name, ms); } else { /* Search in GISBASE */ - snprintf(buf, sizeof(buf), "%s/etc/symbol/%s", G_gisbase(), sname); + snprintf(buf, sizeof(buf), "%s/etc/symbol/%s", G_share_dir(), sname); fp = fopen(buf, "r"); } diff --git a/locale/Makefile b/locale/Makefile index 60b1c8f955f..a17fbfbd1fa 100644 --- a/locale/Makefile +++ b/locale/Makefile @@ -38,7 +38,7 @@ WXPY_POTFILES = find ../gui/wxpython -name '*.py' | xargs grep -l "_(\"\|n_(\"" MOD_PYFILES = find ../scripts -name '*.py' | xargs grep -l "_(\"\|n_(\"" define po_stats -GISBASE="$(RUN_GISBASE)" $(PYTHON) ./grass_po_stats.py +GISBASE="$(RUN_GISBASE)" GRASS_SHAREDIR="$(RUN_GISBASE)" $(PYTHON) ./grass_po_stats.py endef #The xgettext utility is used to automate the creation of diff --git a/locale/grass_po_stats.py b/locale/grass_po_stats.py old mode 100644 new mode 100755 index bfae49629d3..8d28db94833 --- a/locale/grass_po_stats.py +++ b/locale/grass_po_stats.py @@ -160,5 +160,5 @@ def main(in_dirpath, out_josonpath): if __name__ == "__main__": directory = "po/" - outfile = os.path.join(os.environ["GISBASE"], "translation_status.json") + outfile = os.path.join(os.environ["GRASS_SHAREDIR"], "translation_status.json") sys.exit(main(directory, outfile)) diff --git a/man/Makefile b/man/Makefile index 820b8a9f830..0f1b7321f94 100644 --- a/man/Makefile +++ b/man/Makefile @@ -81,35 +81,40 @@ manpages: define build GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ - MDDIR="${MDDIR}" \ + MDDIR="${MDDIR}" GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" \ + GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ $(PYTHON) ./build_$(1).py $(2) endef define build_topics GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ - MDDIR="${MDDIR}" \ + MDDIR="${MDDIR}" GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" \ + GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ $(PYTHON) ./build_topics.py endef define build_keywords GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ - MDDIR="${MDDIR}" \ + MDDIR="${MDDIR}" GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" \ + GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ $(PYTHON) ./build_keywords.py endef define build_graphical_index GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ - MDDIR="${MDDIR}" \ + MDDIR="${MDDIR}" GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" \ + GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ $(PYTHON) ./build_graphical_index.py endef define build_manual_gallery GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ - MDDIR="${MDDIR}" \ + MDDIR="${MDDIR}" GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" \ + GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ $(PYTHON) ./build_manual_gallery.py endef @@ -117,13 +122,15 @@ endef define build_pso GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ + GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ $(PYTHON) ./parser_standard_options.py -t "$(GRASS_HOME)/lib/gis/parser_standard_options.c" \ -f "grass" -o "$(HTMLDIR)/parser_standard_options.html" -p 'id="opts_table" class="scroolTable"' endef define build_pso_md GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ - MDDIR="${MDDIR}" \ + MDDIR="${MDDIR}" GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" \ + GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ $(PYTHON) ./parser_standard_options.py -t "$(GRASS_HOME)/lib/gis/parser_standard_options.c" \ -f "grass" -o "$(MDDIR)/source/parser_standard_options.md" @@ -136,11 +143,13 @@ $(MDDIR)/source/topics.md: $(ALL_MD) define build_class_graphical GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ + GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ $(PYTHON) ./build_class_graphical.py html $(HTMLDIR) endef define build_class_graphical_md GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ + GRASS_DOCDIR="$(ARCH_DISTDIR)/docs/html" GRASS_MKDOCSDIR="$(ARCH_DISTDIR)/docs/mkdocs" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ $(PYTHON) ./build_class_graphical.py md $(MDDIR)/source endef diff --git a/man/build_html.py b/man/build_html.py index 513ef0e2b6b..f2b44e848d3 100644 --- a/man/build_html.py +++ b/man/build_html.py @@ -432,6 +432,6 @@ def get_desc(cmd): ############################################################################ -man_dir = os.path.join(os.environ["ARCH_DISTDIR"], "docs", "html") +man_dir = os.path.join(os.environ["GRASS_DOCDIR"]) ############################################################################ diff --git a/man/build_md.py b/man/build_md.py index bb990c79016..b8e0d84e55d 100644 --- a/man/build_md.py +++ b/man/build_md.py @@ -94,6 +94,6 @@ def get_desc(cmd): ############################################################################ -man_dir = os.path.join(os.environ["ARCH_DISTDIR"], "docs", "mkdocs", "source") +man_dir = os.path.join(os.environ["GRASS_MKDOCSDIR"], "source") ############################################################################ diff --git a/man/build_rest.py b/man/build_rest.py old mode 100644 new mode 100755 index 6cabe95e4e6..04efbe4f2ff --- a/man/build_rest.py +++ b/man/build_rest.py @@ -360,8 +360,8 @@ def get_desc(cmd): arch_dist_dir = os.environ["ARCH_DISTDIR"] rest_dir = os.path.join(arch_dist_dir, "docs", "rest") -gisbase = os.environ["GISBASE"] -ver = read_file(os.path.join(gisbase, "etc", "VERSIONNUMBER")) +grass_share_dir = os.environ["GRASS_SHAREDIR"] +ver = read_file(os.path.join(grass_share_dir, "etc", "VERSIONNUMBER")) try: grass_version = ver.split()[0].strip() except IndexError: diff --git a/ps/ps.map/makeprocs.c b/ps/ps.map/makeprocs.c index ae0bcf9f196..1ea82240dfc 100644 --- a/ps/ps.map/makeprocs.c +++ b/ps/ps.map/makeprocs.c @@ -22,7 +22,8 @@ int make_procs(void) level = (PS.level != 1) ? 2 : 1; fprintf(PS.fp, "/level %d def\n", level); - snprintf(filename, sizeof(filename), "%s/etc/paint/prolog.ps", G_gisbase()); + snprintf(filename, sizeof(filename), "%s/etc/paint/prolog.ps", + G_share_dir()); fp = fopen(filename, "r"); if (!fp) diff --git a/python/grass/CMakeLists.txt b/python/grass/CMakeLists.txt index eeb0be1deb2..c2a1905ec5c 100644 --- a/python/grass/CMakeLists.txt +++ b/python/grass/CMakeLists.txt @@ -1,5 +1,4 @@ set(PYDIRS - app benchmark exceptions grassdb @@ -29,11 +28,25 @@ foreach(pydir ${PYDIRS}) copy_python_files_in_subdir(${pydir} ${PYDIR_GRASS}) endforeach() +# 'app' directory handled separately, because of configuration of +# resource_paths.py +copy_python_files_in_subdir(app ${PYDIR_GRASS} EXCLUDE resource_paths.py) +set(GRASS_PREFIX ${OUTDIR}) +configure_file(app/resource_paths.py.in + ${OUTDIR}/${GRASS_INSTALL_PYDIR}/grass/app/resource_paths.py @ONLY) +set(GRASS_PREFIX ${CMAKE_INSTALL_PREFIX}) +configure_file(app/resource_paths.py.in + ${CMAKE_CURRENT_BINARY_DIR}/resource_paths.py @ONLY) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/resource_paths.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/${GRASS_INSTALL_PYDIR}/grass/app) +unset(GRASS_PREFIX) + configure_file(__init__.py ${OUTDIR}/${PYDIR_GRASS}/ COPYONLY) configure_file(script/setup.py ${OUTDIR}/${PYDIR_GRASS}/script/setup.py COPYONLY) -set(pydir_targets ${PYDIRS}) +set(pydir_targets ${PYDIRS} app) list(TRANSFORM pydir_targets REPLACE "/" "_") list(TRANSFORM pydir_targets PREPEND "python_") diff --git a/python/grass/__init__.py b/python/grass/__init__.py index 32717194453..d6701140677 100644 --- a/python/grass/__init__.py +++ b/python/grass/__init__.py @@ -68,8 +68,7 @@ def _translate(text): try: import gettext # pylint: disable=import-outside-toplevel - gisbase = os.environ["GISBASE"] - locale_dir = os.path.join(gisbase, "locale") + locale_dir = os.environ["GRASS_LOCALEDIR"] # With fallback set to True, not finding the translations files for # a language or domain results in a use of null translation, so this # does not raise an exception even if the locale settings is broken diff --git a/python/grass/app/Makefile b/python/grass/app/Makefile index eebbcef8f12..771100173c1 100644 --- a/python/grass/app/Makefile +++ b/python/grass/app/Makefile @@ -14,7 +14,23 @@ MODULES = \ PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__) PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__) -default: $(PYFILES) $(PYCFILES) +default: $(PYFILES) $(PYCFILES) $(DSTDIR)/resource_paths.py + +$(DSTDIR)/resource_paths.py: resource_paths.py.in + rm -f $@ + sed \ + -e 's#@GRASS_PREFIX@#$(RUN_GISBASE)#' \ + -e 's#@GISBASE@##' \ + -e 's#@GRASS_SHAREDIR@#share#' \ + -e 's#@GRASS_LOCALEDIR@#locale#' \ + -e 's#@GRASS_PYDIR@#etc/python#' \ + -e 's#@GRASS_GUIWXDIR@#gui/wxpython#' \ + -e 's#@GRASS_GUISCRIPTDIR@#gui/scripts#' \ + -e 's#@GRASS_GUIRESDIR@#gui#' \ + -e 's#@GRASS_FONTSDIR@#fonts#' \ + -e 's#@GRASS_ETCDIR@#etc#' \ + $< > $@ + chmod +x $@ $(DSTDIR): $(MKDIR) $@ diff --git a/python/grass/app/data.py b/python/grass/app/data.py index d7d476fec0f..8c42aa7929d 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -99,8 +99,8 @@ def _get_startup_location_in_distribution(): Returns startup location if found or None if nothing was found. """ - gisbase = os.getenv("GISBASE") - startup_location = os.path.join(gisbase, "demolocation") + share_dir = os.getenv("GRASS_SHAREDIR") + startup_location = os.path.join(share_dir, "demolocation") # Find out if startup location exists if os.path.exists(startup_location): @@ -206,15 +206,16 @@ def acquire_mapset_lock( :param message_callback: callback to show messages when locked :param env: system environment variables - The function assumes the `GISBASE` variable is in the environment. The variable is - used to find the lock program. If *env* is not provided, `os.environ` is used. + The function assumes the `GRASS_SHAREDIR` variable is in the environment. + The variable is used to find the lock program. If *env* is not provided, + `os.environ` is used. """ if process_id is None: process_id = os.getpid() if not env: env = os.environ lock_file = os.path.join(mapset_path, ".gislock") - locker_path = os.path.join(env["GISBASE"], "etc", "lock") + locker_path = os.path.join(env["GRASS_ETCDIR"], "lock") total_sleep = 0 try_number = 0 initial_sleep = min(initial_sleep, timeout) diff --git a/python/grass/app/resource_paths.py.in b/python/grass/app/resource_paths.py.in new file mode 100644 index 00000000000..76020bc1ad4 --- /dev/null +++ b/python/grass/app/resource_paths.py.in @@ -0,0 +1,96 @@ +""" + +(C) 2025 by and the GRASS Development Team + +This program is free software under the GNU General Public +License (>=v2). Read the file COPYING that comes with GRASS +for details. + + +This is not a stable part of the API. Use at your own risk. + +The "@...@" variables are being substituted during build process + +""" + +import os + +GRASS_PREFIX = None +GISBASE = None +GRASS_SHAREDIR = None +GRASS_LOCALEDIR = None +GRASS_PYDIR = None +GRASS_GUIWXDIR = None +GRASS_GUISCRIPTDIR = None +GRASS_GUIRESDIR = None +GRASS_FONTSDIR = None +GRASS_ETCDIR = None + +def set_resource_paths(): + + global GRASS_PREFIX + global GISBASE + global GRASS_SHAREDIR + global GRASS_LOCALEDIR + global GRASS_PYDIR + global GRASS_GUIWXDIR + global GRASS_GUISCRIPTDIR + global GRASS_GUIRESDIR + global GRASS_FONTSDIR + global GRASS_ETCDIR + + GRASS_PREFIX = "@GRASS_PREFIX@" + + if "GISBASE" in os.environ and len(os.getenv("GISBASE")) > 0: + GISBASE = os.path.normpath(os.environ["GISBASE"]) + else: + GISBASE = os.path.normpath(os.path.join(GRASS_PREFIX, "@GISBASE@")) + os.environ["GISBASE"] = GISBASE + + if "GRASS_SHAREDIR" in os.environ and len(os.getenv("GRASS_SHAREDIR")) > 0: + GRASS_SHAREDIR = os.path.normpath(os.environ["GRASS_SHAREDIR"]) + else: + GRASS_SHAREDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_SHAREDIR@")) + os.environ["GRASS_SHAREDIR"] = GRASS_SHAREDIR + + if "GRASS_LOCALEDIR" in os.environ and len(os.getenv("GRASS_LOCALEDIR")) > 0: + GRASS_LOCALEDIR = os.path.normpath(os.environ["GRASS_LOCALEDIR"]) + else: + GRASS_LOCALEDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_LOCALEDIR@")) + os.environ["GRASS_LOCALEDIR"] = GRASS_LOCALEDIR + + if "GRASS_PYDIR" in os.environ and len(os.getenv("GRASS_PYDIR")) > 0: + GRASS_PYDIR = os.path.normpath(os.environ["GRASS_PYDIR"]) + else: + GRASS_PYDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_PYDIR@")) + os.environ["GRASS_PYDIR"] = GRASS_PYDIR + + if "GRASS_GUIWXDIR" in os.environ and len(os.getenv("GRASS_GUIWXDIR")) > 0: + GRASS_GUIWXDIR = os.path.normpath(os.environ["GRASS_GUIWXDIR"]) + else: + GRASS_GUIWXDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_GUIWXDIR@")) + os.environ["GRASS_GUIWXDIR"] = GRASS_GUIWXDIR + + if "GRASS_GUISCRIPTDIR" in os.environ and len(os.getenv("GRASS_GUISCRIPTDIR")) > 0: + GRASS_GUISCRIPTDIR = os.path.normpath(os.environ["GRASS_GUISCRIPTDIR"]) + else: + GRASS_GUISCRIPTDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_GUISCRIPTDIR@")) + os.environ["GRASS_GUISCRIPTDIR"] = GRASS_GUISCRIPTDIR + + if "GRASS_GUIRESDIR" in os.environ and len(os.getenv("GRASS_GUIRESDIR")) > 0: + GRASS_GUIRESDIR = os.path.normpath(os.environ["GRASS_GUIRESDIR"]) + else: + GRASS_GUIRESDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_GUIRESDIR@")) + os.environ["GRASS_GUIRESDIR"] = GRASS_GUIRESDIR + + if "GRASS_FONTSDIR" in os.environ and len(os.getenv("GRASS_FONTSDIR")) > 0: + GRASS_FONTSDIR = os.path.normpath(os.environ["GRASS_FONTSDIR"]) + else: + GRASS_FONTSDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_FONTSDIR@")) + os.environ["GRASS_FONTSDIR"] = GRASS_FONTSDIR + + if "GRASS_ETCDIR" in os.environ and len(os.getenv("GRASS_ETCDIR")) > 0: + GRASS_ETCDIR = os.path.normpath(os.environ["GRASS_ETCDIR"]) + else: + GRASS_ETCDIR = os.path.normpath(os.path.join(GRASS_PREFIX, "@GRASS_ETCDIR@")) + os.environ["GRASS_ETCDIR"] = GRASS_ETCDIR diff --git a/python/grass/docs/conf.py b/python/grass/docs/conf.py index 9834d12bd5e..c50afc6376b 100644 --- a/python/grass/docs/conf.py +++ b/python/grass/docs/conf.py @@ -19,58 +19,40 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -if not os.getenv("GISBASE"): - sys.exit("GISBASE not defined") -sys.path.insert( - 0, os.path.abspath(os.path.join(os.environ["GISBASE"], "etc", "python", "grass")) -) +if not os.getenv("GRASS_PYDIR"): + sys.exit("GRASS_PYDIR not defined") +sys.path.insert(0, os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass"))) sys.path.insert( 0, - os.path.abspath( - os.path.join(os.environ["GISBASE"], "etc", "python", "grass", "ctypes") - ), + os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass", "ctypes")), ) sys.path.insert( 0, - os.path.abspath( - os.path.join(os.environ["GISBASE"], "etc", "python", "grass", "exceptions") - ), + os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass", "exceptions")), ) sys.path.insert( 0, - os.path.abspath( - os.path.join(os.environ["GISBASE"], "etc", "python", "grass", "gunittest") - ), + os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass", "gunittest")), ) sys.path.insert( 0, - os.path.abspath( - os.path.join(os.environ["GISBASE"], "etc", "python", "grass", "imaging") - ), + os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass", "imaging")), ) sys.path.insert( 0, - os.path.abspath( - os.path.join(os.environ["GISBASE"], "etc", "python", "grass", "pydispatch") - ), + os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass", "pydispatch")), ) sys.path.insert( 0, - os.path.abspath( - os.path.join(os.environ["GISBASE"], "etc", "python", "grass", "pygrass") - ), + os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass", "pygrass")), ) sys.path.insert( 0, - os.path.abspath( - os.path.join(os.environ["GISBASE"], "etc", "python", "grass", "script") - ), + os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass", "script")), ) sys.path.insert( 0, - os.path.abspath( - os.path.join(os.environ["GISBASE"], "etc", "python", "grass", "temporal") - ), + os.path.abspath(os.path.join(os.environ["GRASS_PYDIR"], "grass", "temporal")), ) from grass.script import core # noqa: E402 diff --git a/python/grass/script/setup.py b/python/grass/script/setup.py index 84c9b95fa36..4b6483802e3 100644 --- a/python/grass/script/setup.py +++ b/python/grass/script/setup.py @@ -107,7 +107,7 @@ def write_gisrc(dbase, location, mapset): def set_gui_path(): """Insert wxPython GRASS path to sys.path.""" - gui_path = os.path.join(os.environ["GISBASE"], "gui", "wxpython") + gui_path = os.environ["GRASS_GUIWXDIR"] if gui_path and gui_path not in sys.path: sys.path.insert(0, gui_path) diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index 5a2d7d18b46..edd9ca759ca 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -424,8 +424,8 @@ def get_lib_path(modname, libname=None): from os import getenv from os.path import isdir, join, sep - if isdir(join(getenv("GISBASE"), "etc", modname)): - path = join(os.getenv("GISBASE"), "etc", modname) + if isdir(join(getenv("GRASS_SHAREDIR"), "etc", modname)): + path = join(os.getenv("GRASS_SHAREDIR"), "etc", modname) elif ( getenv("GRASS_ADDON_BASE") and libname diff --git a/python/grass/semantic_label/reader.py b/python/grass/semantic_label/reader.py index 358e7fafdf9..e3d2b763b52 100644 --- a/python/grass/semantic_label/reader.py +++ b/python/grass/semantic_label/reader.py @@ -23,7 +23,9 @@ class SemanticLabelReader: def __init__(self): self._json_files = glob.glob( - os.path.join(os.environ["GISBASE"], "etc", "i.band.library", "*.json") + os.path.join( + os.environ["GRASS_SHAREDIR"], "etc", "i.band.library", "*.json" + ) ) if not self._json_files: msg = "No semantic label definitions found" diff --git a/python/grass/temporal/core.py b/python/grass/temporal/core.py index 9aa31e8e218..35a69f204e6 100644 --- a/python/grass/temporal/core.py +++ b/python/grass/temporal/core.py @@ -446,8 +446,8 @@ def get_tgis_database_string(): def get_sql_template_path(): - base = os.getenv("GISBASE") - base_etc = os.path.join(base, "etc") + grass_share_dir = os.getenv("GRASS_SHAREDIR") + base_etc = os.path.join(grass_share_dir, "etc") return os.path.join(base_etc, "sql") diff --git a/python/libgrass_interface_generator/CMakeLists.txt b/python/libgrass_interface_generator/CMakeLists.txt index 2da6bfead17..74316a647ae 100644 --- a/python/libgrass_interface_generator/CMakeLists.txt +++ b/python/libgrass_interface_generator/CMakeLists.txt @@ -61,7 +61,6 @@ set(vedit_INCHDRS ${PostgreSQL_INCLUDE_DIRS} ${GDAL_INCLUDE_DIRS}) set(_c_flags ${CMAKE_C_FLAGS}) if(APPLE AND CMAKE_OSX_SYSROOT) string(APPEND _c_flags " --sysroot ${CMAKE_OSX_SYSROOT}") - message("_c_flags") endif() foreach(module ${MODULES}) diff --git a/raster/r.colors/edit_colors.c b/raster/r.colors/edit_colors.c index 6615854b581..5930da91d75 100644 --- a/raster/r.colors/edit_colors.c +++ b/raster/r.colors/edit_colors.c @@ -471,7 +471,7 @@ int edit_colors(int argc, char **argv, int type, const char *maptype, /* check if this style is a percentage style */ /* don't bother with native dirsep as not needed for backwards * compatibility */ - snprintf(path, GPATH_MAX, "%s/etc/colors/%s", G_gisbase(), style); + snprintf(path, GPATH_MAX, "%s/%s", G_colors_dir(), style); rule_is_percent = check_percent_rule(path); do_scale = 1; } @@ -491,7 +491,7 @@ int edit_colors(int argc, char **argv, int type, const char *maptype, /* don't bother with native dirsep as not needed for backwards * compatibility */ - snprintf(path, GPATH_MAX, "%s/etc/colors/%s", G_gisbase(), rules); + snprintf(path, GPATH_MAX, "%s/%s", G_colors_dir(), rules); if (!Rast_load_fp_colors(&colors, path, min, max)) G_fatal_error(_("Unable to load rules file <%s>"), rules); diff --git a/raster/r.watershed/front/main.c b/raster/r.watershed/front/main.c index 2d7cd0283bc..6446cae8e8d 100644 --- a/raster/r.watershed/front/main.c +++ b/raster/r.watershed/front/main.c @@ -261,7 +261,7 @@ int main(int argc, char *argv[]) } /* Build command line */ - snprintf(command, GPATH_MAX, "%s/etc/r.watershed/%s", G_gisbase(), + snprintf(command, GPATH_MAX, "%s/etc/r.watershed/%s", G_share_dir(), flag_seg->answer ? "seg" : "ram"); new_argv[new_argc++] = command; diff --git a/raster/r.watershed/shed/com_line.c b/raster/r.watershed/shed/com_line.c index 287ed7d800e..ab5898f4389 100644 --- a/raster/r.watershed/shed/com_line.c +++ b/raster/r.watershed/shed/com_line.c @@ -54,7 +54,7 @@ int com_line_Gwater(INPUT *input, OUTPUT *output) input->com_line_ram = (char *)G_calloc(400, sizeof(char)); prog_name = G_store(RAM_NAME); snprintf(input->com_line_ram, (400 * sizeof(char)), - "\"%s/etc/water/%s\"", G_gisbase(), RAM_NAME); + "\"%s/etc/water/%s\"", G_share_dir(), RAM_NAME); fprintf(stderr, "\nIf there is not enough ram for the fast mode (%s) to run,\n", RAM_NAME); @@ -64,7 +64,7 @@ int com_line_Gwater(INPUT *input, OUTPUT *output) input->slow = 1; input->com_line_seg = (char *)G_calloc(400, sizeof(char)); snprintf(input->com_line_seg, (400, sizeof(char)), - "\"%s/etc/water/%s\"", G_gisbase(), SEG_NAME); + "\"%s/etc/water/%s\"", G_share_dir(), SEG_NAME); } } else { @@ -72,7 +72,7 @@ int com_line_Gwater(INPUT *input, OUTPUT *output) prog_name = G_store(SEG_NAME); input->com_line_seg = (char *)G_calloc(400, sizeof(char)); snprintf(input->com_line_seg, (400, sizeof(char)), - "\"%s/etc/water/%s\"", G_gisbase(), SEG_NAME); + "\"%s/etc/water/%s\"", G_share_dir(), SEG_NAME); } G_message(_("\nIf you hit by itself for the next question, this")); diff --git a/scripts/d.polar/d.polar.py b/scripts/d.polar/d.polar.py index 2d5f6d50a7b..74da2207c37 100755 --- a/scripts/d.polar/d.polar.py +++ b/scripts/d.polar/d.polar.py @@ -236,7 +236,7 @@ def plot_eps(psout): ########## outf = open(psout, "w") - prolog = os.path.join(os.environ["GISBASE"], "etc", "d.polar", "ps_defs.eps") + prolog = os.path.join(os.environ["GRASS_SHAREDIR"], "etc", "d.polar", "ps_defs.eps") inf = open(prolog) shutil.copyfileobj(inf, outf) inf.close() diff --git a/scripts/db.test/db.test.py b/scripts/db.test/db.test.py index c4ed7d99c54..eedb5565360 100755 --- a/scripts/db.test/db.test.py +++ b/scripts/db.test/db.test.py @@ -43,7 +43,7 @@ def main(): dbconn = grassdb.db_connection() gcore.message(_("Using DB driver: %s") % dbconn["driver"]) - infile = os.path.join(os.environ["GISBASE"], "etc", "db.test", test_file) + infile = os.path.join(os.environ["GRASS_SHAREDIR"], "etc", "db.test", test_file) inf = open(infile) while True: diff --git a/scripts/g.search.modules/g.search.modules.py b/scripts/g.search.modules/g.search.modules.py index 76a8c4d1f3e..f9ab0513148 100755 --- a/scripts/g.search.modules/g.search.modules.py +++ b/scripts/g.search.modules/g.search.modules.py @@ -213,7 +213,7 @@ def _search_module( items.extend(addon_items) # add system-wide installed addons to modules list - filename_addons_s = os.path.join(os.getenv("GISBASE"), "modules.xml") + filename_addons_s = os.path.join(os.getenv("GRASS_SHAREDIR"), "modules.xml") if os.path.isfile(filename_addons_s): with open(filename_addons_s) as addon_menudata_file_s: addon_menudata_s = ET.parse(addon_menudata_file_s) diff --git a/scripts/wxpyimgview/wxpyimgview.py b/scripts/wxpyimgview/wxpyimgview.py old mode 100644 new mode 100755 index ac848791c80..1bcae65740e --- a/scripts/wxpyimgview/wxpyimgview.py +++ b/scripts/wxpyimgview/wxpyimgview.py @@ -45,6 +45,6 @@ image = options["image"] percent = options["percent"] python = os.getenv("GRASS_PYTHON", "python") - gisbase = os.environ["GISBASE"] - script = os.path.join(gisbase, "etc", "wxpyimgview_gui.py") + grass_share_dir = os.environ["GRASS_SHAREDIR"] + script = os.path.join(grass_share_dir, "etc", "wxpyimgview_gui.py") os.execlp(python, script, script, image, percent) diff --git a/utils/thumbnails.py b/utils/thumbnails.py index c04c806bb13..8e670172919 100755 --- a/utils/thumbnails.py +++ b/utils/thumbnails.py @@ -158,7 +158,7 @@ def main(): os.environ["GRASS_OVERWRITE"] = "1" - color_dir = os.path.join(os.environ["GISBASE"], "etc", "colors") + color_dir = os.environ["GRASS_COLORSDIR"] output_dir = sys.argv[1] if not os.path.exists(output_dir): diff --git a/vector/v.label.sa/font.c b/vector/v.label.sa/font.c index c99c7995d79..4fb684358d0 100644 --- a/vector/v.label.sa/font.c +++ b/vector/v.label.sa/font.c @@ -55,7 +55,7 @@ struct GFONT_CAP *find_font_from_freetypecap(const char *font) capfile); } if (fp == NULL) { - snprintf(file, sizeof(file), "%s/etc/fontcap", G_gisbase()); + snprintf(file, sizeof(file), "%s/etc/fontcap", G_share_dir()); if ((fp = fopen(file, "r")) == NULL) G_warning(_("%s: No font definition file"), file); }