Cmake File COPY across drives - windows

The following does not work:
cmake file ( copy "C:/pathtofile/file.file" DESTINATION "D:/pathtofile2/file2.file" )
Is there a way to achieve the same thing using cmake?

The documentation states that DESTINATION has to be a directory. Therefore renaming the file does not work this way.
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "C:/pathtofile/file.file" "D:/pathtofile2/file2.file")
should work.

cmakes fantastic Configure file system will work. The files can have different names, but basically if it finds any variables that can be expanded by cmake like ${cmake_root_dir} or $ENV{localappdata}, it will edit the file, replace the variables with their values and save it to the new location under the new name. So if there are no variables it just copies.
Configure_file( C:/pathtofile/file.file" "D:/pathtofile2/file2.file")
If you have cmake style variables in there for whatever reason and you don't want them expanded, use #Only as it will only expand variables surrounded by "#":
Configure_file( C:/pathtofile/file.file" "D:/pathtofile2/file2.file" #ONLY)

Related

sql loader without .dat extension

Oracle's sqlldr defaults to a .dat extension. That I want to override. I don't like to rename the file. When googled get to know few answers to use . like data='fileName.' which is not working. Share your ideas, please.
Error message is fileName.dat is not found.
Sqlloder has default extension for all input files data,log,control...
data= .dat
log= .log
control = .ctl
bad =.bad
PARFILE = .par
But you have to pass filename without apostrophe and dot
sqlloder pass/user#db control=control data=data
sqloader will add extension. control.ctl data.dat
Nevertheless i do not understand why you do not want to specify extension?
You can't, at least in Unix/Linux environments. In Windows you can use the trailing period trick, specifying either INFILE 'filename.' in the control file or DATA=filename. on the command line. WIndows file name handling allows that; you can for instance do DIR filename. at a command prompt and it will list the file with no extension (as will DIR filename). But you can't do that with *nix, from a shell prompt or anywhere else.
You said you don't want to copy or rename the file. Temporarily renaming it might be the simplest solution, but as you may have a reason not to do that even briefly you could instead create a hard or soft link to the file which does have an extension, and use that link as the target instead. You could wrap that in a shell script that takes the file name argument:
# set variable from correct positional parameter; if you pass in the control
# file name or other options, this might not be $1 so adjust as needed
# if the tmeproary file won't be int he same directory, need to be full path
filename=$1
# optionally check file exists, is readable, etc. but overkill for demo
# can also check temporary file does not already exist - stop or remove
# create soft link somewhere it won't impact any other processes
ln -s ${filename} /tmp/${filename##*/}.dat
# run SQL*Loader with soft link as target
sqlldr user/password#db control=file.ctl data=/tmp/${filename##*/}.dat
# clean up
rm -f /tmp/${filename##*/}.dat
You can then call that as:
./scriptfile.sh /path/to/filename
If you can create the link in the same directory then you only need to pass the file, but if it's somewhere else - which may be necessary depending on why renaming isn't an option, and desirable either way - then you need to pass the full path of the data file so the link works. (If the temporary file will be int he same filesystem you could use a hard link, and you wouldn't have to pass the full path then either, but it's still cleaner to do so).
As you haven't shown your current command line options you may have to adjust that to take into account anything else you currently specify there rather than in the control file, particularly which positional argument is actually the data file path.
I have the same issue. I get a monthly download of reference data used in medical application and the 485 downloaded files don't have file extensions (#2gb). Unless I can load without file extensions I have to copy the files with .dat and load from there.

cmake: how to create visual studio filters

I have already looked around (StackOverflow and more) and I'm trying to use cmake to generate Visual Studio filters. I have the following folders:
src/math
src/import
src/ui
I would like to generate the filters like above.
math: contains all the cpp & h files in src/math
import: contains all the cpp & h files in src/import
ui: contains all the cpp & h files in src/ui
I have tried several solutions, but none seems to work!!!
Here is the last version of the code in CMakeList.txt:
set(VD_SRC "${VisualDesigner_SOURCE_DIR}/src/visualdesigner")
file(GLOB_RECURSE SRC_UI
"${VD_SRC}/ui/*.cpp", "${VD_SRC}/ui/*.h")
file(GLOB_RECURSE SRC_IMPORT
"${VD_SRC}/import/*.cpp",
"${VD_SRC}/import/*.h")
source_group("ui" FILES ${SRC_UI})
source_group("import" FILES ${SRC_IMPORT})
Any help is welcomed!
See How to set Visual Studio Filters for nested sub directory using cmake
Just be aware that
the source_group() command only works in combination with add_library() or add_executable() commands listing the same sources (the paths must match)
the source_group() command does not check if the file actually exists (so it takes anything you give it and during project file generation it tries to match the given source group file names against files used in the project)
I have given your code a try by adding a corresponding add_library() target and it works as expected (CMake 3.3.2 and VS2015):
set(VD_SRC "${VisualDesigner_SOURCE_DIR}/src/visualdesigner")
file(GLOB_RECURSE SRC_UI
"${VD_SRC}/ui/*.cpp"
"${VD_SRC}/ui/*.h"
)
file(GLOB_RECURSE SRC_IMPORT
"${VD_SRC}/import/*.cpp"
"${VD_SRC}/import/*.h"
)
add_library(VisalDesigner ${SRC_UI} ${SRC_IMPORT})
source_group("ui" FILES ${SRC_UI})
source_group("import" FILES ${SRC_IMPORT})
Results in
Here is a more generalized version taken from Visual Studio as an editor for CMake friendly project:
set(_src_root_path "${VisualDesigner_SOURCE_DIR}/src/visualdesigner")
file(
GLOB_RECURSE _source_list
LIST_DIRECTORIES false
"${_src_root_path}/*.c*"
"${_src_root_path}/*.h*"
)
add_library(VisualDesigner ${_source_list})
foreach(_source IN ITEMS ${_source_list})
get_filename_component(_source_path "${_source}" PATH)
file(RELATIVE_PATH _source_path_rel "${_src_root_path}" "${_source_path}")
string(REPLACE "/" "\\" _group_path "${_source_path_rel}")
source_group("${_group_path}" FILES "${_source}")
endforeach()
I found it easier to do this and thought it might be helpful to others. Make sure you are using the latest version of CMAKE.
file(GLOB_RECURSE _source_list *.cpp* *.h* *.hpp*)
foreach(_source IN ITEMS ${_source_list})
get_filename_component(_source_path "${_source}" PATH)
string(REPLACE "${CMAKE_SOURCE_DIR}" "" _group_path "${_source_path}")
string(REPLACE "/" "\\" _group_path "${_group_path}")
source_group("${_group_path}" FILES "${_source}")
endforeach()
As of CMake 3.8, the source_group command offers a TREE argument to recursively search the files paths of your sources to structure the source groups to match your file system structure. Now, the solution is a lot cleaner, no need for looping:
set(VD_SRC "${VisualDesigner_SOURCE_DIR}/src/visualdesigner")
file(GLOB_RECURSE UI_IMPORT_MATH_SRCS
"${VD_SRC}/ui/*.cpp"
"${VD_SRC}/ui/*.h"
"${VD_SRC}/import/*.cpp"
"${VD_SRC}/import/*.h"
"${VD_SRC}/math/*.cpp"
"${VD_SRC}/math/*.h"
)
add_library(VisualDesigner ${UI_IMPORT_MATH_SRCS})
# Create the source groups for source tree with root at VD_SRC.
source_group(TREE ${VD_SRC} FILES ${UI_IMPORT_MATH_SRCS})
Also, check out the new PREFIX argument you can use with source_group if you find that useful.
Disclaimer: I advise against the use of GLOB (see here) wherever possible.
For those, who want to create them under "Header Files" and "Source Files":
You can use source_group. Here's a concrete example.
Suppose you have a directory structure like:
|-include
| some.h
|-sub
| someother.h
|-src
| some.cpp
|-sub
|-someother.cpp
Collect the files (some people - including the documentation - discourages use of GLOB, but I leave that to you, you can list of them one by if you want to, though I find GLOB is just fine many times):
file(GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h")
file(GLOB HEADER_FILES_SUB "${CMAKE_CURRENT_SOURCE_DIR}/include/sub/*.h")
file(GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")
file(GLOB SOURCE_FILES_SUB "${CMAKE_CURRENT_SOURCE_DIR}/src/sub/*.h")
# Setup your library or executable:
add_library(MY_LIB ${HEADER_FILES} ${HEADER_FILES_SUB}
${SOURCE_FILES} ${SOURCE_FILES_SUB})
# Here's the important part ("Header Files" and "Source Files" are literals.)
source_group("Header Files\\sub" ${HEADER_FILES_SUB})
source_group("Source Files\\sub" ${SOURCE_FILES_SUB})
All of the above answers work in general. If you have multiple library targets and wish to create fancy filters for each of the targets, then you need to be a bit careful.
After quite a lot of headbanging, I figured you should keep the source_group call in the same CMakeLists.txt file where you did an add_library(target ..) or add_executable(target ..). You can cache (internal) the "source\header lists" anywhere and use it here.

How to input a parameter in a custom target with cmake

I have a custom target:
add_custom_target(
create-po
COMMAND ${MSGINIT} --no-translator -i "${PROJECT_SOURCE_DIR}/data/${PACKAGE}.pot" - "${PROJECT_SOURCE_DIR}/po/es.po" -l es_MX.utf8
)
so, is invoked like this:
# make create-po
my idea is to change it to something like this:
# make create-po "es"
so, any user can create a custom localed po file. I don't know the word exactly for this, but I'd like to add a parameter in the target name..is it posible with cmake? Thanks
After so long time I found this question for the same reason: Can I use CMake to initialize a .po file if I want to add a new translation? I expect to use it only once in a while for my project, so make the build system do it seems more comfortable to me than find out all the required options and paths every time.
I ended up with the following CMake snippet:
set(INIT_LANG CACHE STRING "give a locale here to create a target which initializes a related .po file")
IF(INIT_LANG)
add_custom_target(
create-po-${INIT_LANG}
... # integrate INIT_LANG in your command
)
ENDIF(INIT_LANG)
Then, if you want to initialize a new translation file, call (assuming your build dir in under the project root):
# cmake -DINIT_LANG=es_MX.utf8 ..
... and you should get a corresponding make target:
# make create-po-es_MX.utf8
Yes, it's not as straight-forward as the OP's idea/expectation (and mine as well), but users can create new .po files by themselves (of course, this will be documented properly for them in the project ;) ).

Using CMake, how can I concat files and install them

I'm new to CMake and I have a problem that I can not figure out a solution to. I'm using CMake to compile a project with a bunch of optional sub-dirs and it builds shared library files as expected. That part seems to be working fine. Each of these sub-dirs contains a sql file. I need to concat all the selected sql files to one sql header file and install the result. So one file like:
sql_header.sql
sub_dir_A.sql
sub_dir_C.sql
sub_dir_D.sql
If I did this directly in a make file I might do something like the following only smarter to deal with only the selected sub-dirs:
cat sql_header.sql > "${INSTALL_PATH}/somefile.sql"
cat sub_dir_A.sql >> "${INSTALL_PATH}/somefile.sql"
cat sub_dir_C.sql >> "${INSTALL_PATH}/somefile.sql"
cat sub_dir_D.sql >> "${INSTALL_PATH}/somefile.sql"
I have sort of figured out pieces of this, like I can use:
LIST(APPEND PACKAGE_SQL_FILES "some_file.sql")
which I assume I can place in each of the sub-dirs CMakeLists.txt files to collect the file names. And I can create a macro like:
CAT(IN "${PACKAGE_SQL_FILES}" OUT "${INSTALL_PATH}/somefile.sql")
But I am lost between when the CMake initially runs and when it runs from the make install. Maybe there is a better way to do this. I need this to work on both Windows and Linux.
I would be happy with some hints to point me in the right direction.
You can create the concatenated file mainly using CMake's file and function commands.
First, create a cat function:
function(cat IN_FILE OUT_FILE)
file(READ ${IN_FILE} CONTENTS)
file(APPEND ${OUT_FILE} "${CONTENTS}")
endfunction()
Assuming you have the list of input files in the variable PACKAGE_SQL_FILES, you can use the function like this:
# Prepare a temporary file to "cat" to:
file(WRITE somefile.sql.in "")
# Call the "cat" function for each input file
foreach(PACKAGE_SQL_FILE ${PACKAGE_SQL_FILES})
cat(${PACKAGE_SQL_FILE} somefile.sql.in)
endforeach()
# Copy the temporary file to the final location
configure_file(somefile.sql.in somefile.sql COPYONLY)
The reason for writing to a temporary is so the real target file only gets updated if its content has changed. See this answer for why this is a good thing.
You should note that if you're including the subdirectories via the add_subdirectory command, the subdirs all have their own scope as far as CMake variables are concerned. In the subdirs, using list will only affect variables in the scope of that subdir.
If you want to create a list available in the parent scope, you'll need to use set(... PARENT_SCOPE), e.g.
set(PACKAGE_SQL_FILES
${PACKAGE_SQL_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/some_file.sql
PARENT_SCOPE)
All this so far has simply created the concatenated file in the root of your build tree. To install it, you probably want to use the install(FILES ...) command:
install(FILES ${CMAKE_BINARY_DIR}/somefile.sql
DESTINATION ${INSTALL_PATH})
So, whenever CMake runs (either because you manually invoke it or because it detects changes when you do "make"), it will update the concatenated file in the build tree. Only once you run "make install" will the file finally be copied from the build root to the install location.
As of CMake 3.18, the CMake command line tool can concatenate files using cat. So, assuming a variable PACKAGE_SQL_FILES containing the list of files, you can run the cat command using execute_process:
# Concatenate the sql files into a variable 'FINAL_FILE'.
execute_process(COMMAND ${CMAKE_COMMAND} -E cat ${PACKAGE_SQL_FILES}
OUTPUT_VARIABLE FINAL_FILE
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
# Write out the concatenated contents to 'final.sql.in'.
file(WRITE final.sql.in ${FINAL_FILE})
The rest of the solution is similar to Fraser's response. You can use configure_file so the resultant file is only updated when necessary.
configure_file(final.sql.in final.sql COPYONLY)
You can still use install in the same way to install the file:
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/final.sql
DESTINATION ${INSTALL_PATH})

Automatically generate conf file during make

I have a conf file that is of the format:
name=value
What I want to do is using a template, generate a result based on some values in another file.
So for example, say I have a file called PATHS that contains
CONF_DIR=/etc
BIN_DIR=/usr/sbin
LOG_DIR=/var/log
CACHE_DIR=/home/cache
This PATHS file gets included into a Makefile so that when I call make install the paths are created and built applications and conf files copied appropriately.
Now I also have a conf file which I want to use as a template.
Say the template contains lines like
LogFile=$(LOG_DIR)/myapp.log
...
Then generate a destination conf that would have
LogFile=/var/log/myapp.log
...
etc
I think this can be done with a sed script, but I'm not very familiar with sed and regular expression syntax. I will accept a shell script version too.
You should definitely go with autoconf here, whose very job is to do this. You'll have to write a conf.in file, wherein all substitutions are marked with #'s, e.g.
prefix=#prefix#
bindir=#bindir#
and write up a configure.ac, which is a shell script that will perform these substitutions for you and create conf. conf is subsequently included in the Makefile. I'd even recommend using a Makefile.in file, i.e. including your snippet in the Makefile.
If you keep to the standard path names, your configure.ac is a four-liner and has the added advantage of being GNU compatible (easy to understand & use).
You may want to consider using m4 as a simple template language instead.

Resources