Compare commits
No commits in common. "master" and "wsjtx-2.4.0-rc2" have entirely different histories.
master
...
wsjtx-2.4.
@ -97,7 +97,7 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi
|
||||
m_stream->start (sink);
|
||||
checkStream ();
|
||||
cummulative_lost_usec_ = -1;
|
||||
// LOG_DEBUG ("Selected buffer size (bytes): " << m_stream->bufferSize () << " period size: " << m_stream->periodSize ());
|
||||
LOG_DEBUG ("Selected buffer size (bytes): " << m_stream->bufferSize () << " period size: " << m_stream->periodSize ());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -180,15 +180,13 @@ void SoundInput::reset (bool report_dropped_frames)
|
||||
if (cummulative_lost_usec_ != std::numeric_limits<qint64>::min () && report_dropped_frames)
|
||||
{
|
||||
auto lost_usec = elapsed_usecs - m_stream->processedUSecs () - cummulative_lost_usec_;
|
||||
// disable log warnings on dropped audio for now, as detection is not reliable
|
||||
// if (std::abs (lost_usec) > 48000 / 5)
|
||||
// {
|
||||
// LOG_WARN ("Detected dropped audio source samples: "
|
||||
// << m_stream->format ().framesForDuration (lost_usec)
|
||||
// << " (" << std::setprecision (4) << lost_usec / 1.e6 << " S)");
|
||||
// }
|
||||
// else if (std::abs (lost_usec) > 5 * 48000)
|
||||
if (std::abs (lost_usec) > 5 * 48000)
|
||||
if (std::abs (lost_usec) > 48000 / 5)
|
||||
{
|
||||
LOG_WARN ("Detected dropped audio source samples: "
|
||||
<< m_stream->format ().framesForDuration (lost_usec)
|
||||
<< " (" << std::setprecision (4) << lost_usec / 1.e6 << " S)");
|
||||
}
|
||||
else if (std::abs (lost_usec) > 5 * 48000)
|
||||
{
|
||||
LOG_ERROR ("Detected excessive dropped audio source samples: "
|
||||
<< m_stream->format ().framesForDuration (lost_usec)
|
||||
|
@ -111,7 +111,7 @@ void SoundOutput::restart (QIODevice * source)
|
||||
}
|
||||
m_stream->setCategory ("production");
|
||||
m_stream->start (source);
|
||||
// LOG_DEBUG ("Selected buffer size (bytes): " << m_stream->bufferSize () << " period size: " << m_stream->periodSize ());
|
||||
LOG_DEBUG ("Selected buffer size (bytes): " << m_stream->bufferSize () << " period size: " << m_stream->periodSize ());
|
||||
}
|
||||
|
||||
void SoundOutput::suspend ()
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <locale>
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QTextStream>
|
||||
@ -238,9 +239,11 @@ int main(int argc, char *argv[])
|
||||
QCoreApplication app {argc, argv};
|
||||
try
|
||||
{
|
||||
// ensure number forms are in consistent format, do this after
|
||||
// instantiating QApplication so that Qt has correct l18n
|
||||
std::locale::global (std::locale::classic ());
|
||||
::setlocale (LC_NUMERIC, "C"); // ensure number forms are in
|
||||
// consistent format, do this
|
||||
// after instantiating
|
||||
// QApplication so that Qt has
|
||||
// correct l18n
|
||||
|
||||
// Override programs executable basename as application name.
|
||||
app.setApplicationName ("WSJT-X Record Time Signal");
|
||||
|
975
CMake/Modules/BundleUtilities.cmake
Normal file
@ -0,0 +1,975 @@
|
||||
#.rst:
|
||||
# BundleUtilities
|
||||
# ---------------
|
||||
#
|
||||
# Functions to help assemble a standalone bundle application.
|
||||
#
|
||||
# A collection of CMake utility functions useful for dealing with .app
|
||||
# bundles on the Mac and bundle-like directories on any OS.
|
||||
#
|
||||
# The following functions are provided by this module:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# fixup_bundle
|
||||
# copy_and_fixup_bundle
|
||||
# verify_app
|
||||
# get_bundle_main_executable
|
||||
# get_dotapp_dir
|
||||
# get_bundle_and_executable
|
||||
# get_bundle_all_executables
|
||||
# get_item_key
|
||||
# get_item_rpaths
|
||||
# clear_bundle_keys
|
||||
# set_bundle_key_values
|
||||
# get_bundle_keys
|
||||
# copy_resolved_item_into_bundle
|
||||
# copy_resolved_framework_into_bundle
|
||||
# fixup_bundle_item
|
||||
# verify_bundle_prerequisites
|
||||
# verify_bundle_symlinks
|
||||
#
|
||||
# Requires CMake 2.6 or greater because it uses function, break and
|
||||
# PARENT_SCOPE. Also depends on GetPrerequisites.cmake.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# FIXUP_BUNDLE(<app> <libs> <dirs>)
|
||||
#
|
||||
# Fix up a bundle in-place and make it standalone, such that it can be
|
||||
# drag-n-drop copied to another machine and run on that machine as long
|
||||
# as all of the system libraries are compatible.
|
||||
#
|
||||
# If you pass plugins to fixup_bundle as the libs parameter, you should
|
||||
# install them or copy them into the bundle before calling fixup_bundle.
|
||||
# The "libs" parameter is a list of libraries that must be fixed up, but
|
||||
# that cannot be determined by otool output analysis. (i.e., plugins)
|
||||
#
|
||||
# Gather all the keys for all the executables and libraries in a bundle,
|
||||
# and then, for each key, copy each prerequisite into the bundle. Then
|
||||
# fix each one up according to its own list of prerequisites.
|
||||
#
|
||||
# Then clear all the keys and call verify_app on the final bundle to
|
||||
# ensure that it is truly standalone.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>)
|
||||
#
|
||||
# Makes a copy of the bundle <src> at location <dst> and then fixes up
|
||||
# the new copied bundle in-place at <dst>...
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# VERIFY_APP(<app>)
|
||||
#
|
||||
# Verifies that an application <app> appears valid based on running
|
||||
# analysis tools on it. Calls "message(FATAL_ERROR" if the application
|
||||
# is not verified.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>)
|
||||
#
|
||||
# The result will be the full path name of the bundle's main executable
|
||||
# file or an "error:" prefixed string if it could not be determined.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>)
|
||||
#
|
||||
# Returns the nearest parent dir whose name ends with ".app" given the
|
||||
# full path to an executable. If there is no such parent dir, then
|
||||
# simply return the dir containing the executable.
|
||||
#
|
||||
# The returned directory may or may not exist.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>)
|
||||
#
|
||||
# Takes either a ".app" directory name or the name of an executable
|
||||
# nested inside a ".app" directory and returns the path to the ".app"
|
||||
# directory in <bundle_var> and the path to its main executable in
|
||||
# <executable_var>
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>)
|
||||
#
|
||||
# Scans the given bundle recursively for all executable files and
|
||||
# accumulates them into a variable.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GET_ITEM_KEY(<item> <key_var>)
|
||||
#
|
||||
# Given a file (item) name, generate a key that should be unique
|
||||
# considering the set of libraries that need copying or fixing up to
|
||||
# make a bundle standalone. This is essentially the file name including
|
||||
# extension with "." replaced by "_"
|
||||
#
|
||||
# This key is used as a prefix for CMake variables so that we can
|
||||
# associate a set of variables with a given item based on its key.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# CLEAR_BUNDLE_KEYS(<keys_var>)
|
||||
#
|
||||
# Loop over the list of keys, clearing all the variables associated with
|
||||
# each key. After the loop, clear the list of keys itself.
|
||||
#
|
||||
# Caller of get_bundle_keys should call clear_bundle_keys when done with
|
||||
# list of keys.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs>
|
||||
# <copyflag> [<rpaths>])
|
||||
#
|
||||
# Add a key to the list (if necessary) for the given item. If added,
|
||||
# also set all the variables associated with that key.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>)
|
||||
#
|
||||
# Loop over all the executable and library files within the bundle (and
|
||||
# given as extra <libs>) and accumulate a list of keys representing
|
||||
# them. Set values associated with each key such that we can loop over
|
||||
# all of them and copy prerequisite libs into the bundle and then do
|
||||
# appropriate install_name_tool fixups.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
|
||||
#
|
||||
# Copy a resolved item into the bundle if necessary. Copy is not
|
||||
# necessary if the resolved_item is "the same as" the
|
||||
# resolved_embedded_item.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
|
||||
#
|
||||
# Copy a resolved framework into the bundle if necessary. Copy is not
|
||||
# necessary if the resolved_item is "the same as" the
|
||||
# resolved_embedded_item.
|
||||
#
|
||||
# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want
|
||||
# full frameworks embedded in your bundles, set
|
||||
# BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By
|
||||
# default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework
|
||||
# dylib itself plus the framework Resources directory.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>)
|
||||
#
|
||||
# Get the direct/non-system prerequisites of the resolved embedded item.
|
||||
# For each prerequisite, change the way it is referenced to the value of
|
||||
# the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely
|
||||
# changing to an "@executable_path" style reference.)
|
||||
#
|
||||
# This function requires that the resolved_embedded_item be "inside" the
|
||||
# bundle already. In other words, if you pass plugins to fixup_bundle
|
||||
# as the libs parameter, you should install them or copy them into the
|
||||
# bundle before calling fixup_bundle. The "libs" parameter is a list of
|
||||
# libraries that must be fixed up, but that cannot be determined by
|
||||
# otool output analysis. (i.e., plugins)
|
||||
#
|
||||
# Also, change the id of the item being fixed up to its own
|
||||
# _EMBEDDED_ITEM value.
|
||||
#
|
||||
# Accumulate changes in a local variable and make *one* call to
|
||||
# install_name_tool at the end of the function with all the changes at
|
||||
# once.
|
||||
#
|
||||
# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be
|
||||
# marked writable before install_name_tool tries to change them.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>)
|
||||
#
|
||||
# Verifies that the sum of all prerequisites of all files inside the
|
||||
# bundle are contained within the bundle or are "system" libraries,
|
||||
# presumed to exist everywhere.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>)
|
||||
#
|
||||
# Verifies that any symlinks found in the bundle point to other files
|
||||
# that are already also in the bundle... Anything that points to an
|
||||
# external file causes this function to fail the verification.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2008-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# The functions defined in this file depend on the get_prerequisites function
|
||||
# (and possibly others) found in:
|
||||
#
|
||||
get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
include("${BundleUtilities_cmake_dir}/GetPrerequisites.cmake")
|
||||
|
||||
|
||||
function(get_bundle_main_executable bundle result_var)
|
||||
set(result "error: '${bundle}/Contents/Info.plist' file does not exist")
|
||||
|
||||
if(EXISTS "${bundle}/Contents/Info.plist")
|
||||
set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file")
|
||||
set(line_is_main_executable 0)
|
||||
set(bundle_executable "")
|
||||
|
||||
# Read Info.plist as a list of lines:
|
||||
#
|
||||
set(eol_char "E")
|
||||
file(READ "${bundle}/Contents/Info.plist" info_plist)
|
||||
string(REPLACE ";" "\\;" info_plist "${info_plist}")
|
||||
string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}")
|
||||
string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}")
|
||||
|
||||
# Scan the lines for "<key>CFBundleExecutable</key>" - the line after that
|
||||
# is the name of the main executable.
|
||||
#
|
||||
foreach(line ${info_plist})
|
||||
if(line_is_main_executable)
|
||||
string(REGEX REPLACE "^.*<string>(.*)</string>.*$" "\\1" bundle_executable "${line}")
|
||||
break()
|
||||
endif()
|
||||
|
||||
if(line MATCHES "<key>CFBundleExecutable</key>")
|
||||
set(line_is_main_executable 1)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT "${bundle_executable}" STREQUAL "")
|
||||
if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}")
|
||||
set(result "${bundle}/Contents/MacOS/${bundle_executable}")
|
||||
else()
|
||||
|
||||
# Ultimate goal:
|
||||
# If not in "Contents/MacOS" then scan the bundle for matching files. If
|
||||
# there is only one executable file that matches, then use it, otherwise
|
||||
# it's an error...
|
||||
#
|
||||
#file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}")
|
||||
|
||||
# But for now, pragmatically, it's an error. Expect the main executable
|
||||
# for the bundle to be in Contents/MacOS, it's an error if it's not:
|
||||
#
|
||||
set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
#
|
||||
# More inclusive technique... (This one would work on Windows and Linux
|
||||
# too, if a developer followed the typical Mac bundle naming convention...)
|
||||
#
|
||||
# If there is no Info.plist file, try to find an executable with the same
|
||||
# base name as the .app directory:
|
||||
#
|
||||
endif()
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_dotapp_dir exe dotapp_dir_var)
|
||||
set(s "${exe}")
|
||||
|
||||
if(s MATCHES "/.*\\.app/")
|
||||
# If there is a ".app" parent directory,
|
||||
# ascend until we hit it:
|
||||
# (typical of a Mac bundle executable)
|
||||
#
|
||||
set(done 0)
|
||||
while(NOT ${done})
|
||||
get_filename_component(snamewe "${s}" NAME_WE)
|
||||
get_filename_component(sname "${s}" NAME)
|
||||
get_filename_component(sdir "${s}" PATH)
|
||||
set(s "${sdir}")
|
||||
if(sname MATCHES "\\.app$")
|
||||
set(done 1)
|
||||
set(dotapp_dir "${sdir}/${sname}")
|
||||
endif()
|
||||
endwhile()
|
||||
else()
|
||||
# Otherwise use a directory containing the exe
|
||||
# (typical of a non-bundle executable on Mac, Windows or Linux)
|
||||
#
|
||||
is_file_executable("${s}" is_executable)
|
||||
if(is_executable)
|
||||
get_filename_component(sdir "${s}" PATH)
|
||||
set(dotapp_dir "${sdir}")
|
||||
else()
|
||||
set(dotapp_dir "${s}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_and_executable app bundle_var executable_var valid_var)
|
||||
set(valid 0)
|
||||
|
||||
if(EXISTS "${app}")
|
||||
# Is it a directory ending in .app?
|
||||
if(IS_DIRECTORY "${app}")
|
||||
if(app MATCHES "\\.app$")
|
||||
get_bundle_main_executable("${app}" executable)
|
||||
if(EXISTS "${app}" AND EXISTS "${executable}")
|
||||
set(${bundle_var} "${app}" PARENT_SCOPE)
|
||||
set(${executable_var} "${executable}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled .app directory case...")
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - .app directory case...")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - directory but not .app case...")
|
||||
endif()
|
||||
else()
|
||||
# Is it an executable file?
|
||||
is_file_executable("${app}" is_executable)
|
||||
if(is_executable)
|
||||
get_dotapp_dir("${app}" dotapp_dir)
|
||||
if(EXISTS "${dotapp_dir}")
|
||||
set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE)
|
||||
set(${executable_var} "${app}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled executable file in .app dir case...")
|
||||
else()
|
||||
get_filename_component(app_dir "${app}" PATH)
|
||||
set(${bundle_var} "${app_dir}" PARENT_SCOPE)
|
||||
set(${executable_var} "${app}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled executable file in any dir case...")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - not .app dir, not executable file...")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - directory/file does not exist...")
|
||||
endif()
|
||||
|
||||
if(NOT valid)
|
||||
set(${bundle_var} "error: not a bundle" PARENT_SCOPE)
|
||||
set(${executable_var} "error: not a bundle" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
set(${valid_var} ${valid} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_all_executables bundle exes_var)
|
||||
set(exes "")
|
||||
|
||||
if(UNIX)
|
||||
find_program(find_cmd "find")
|
||||
mark_as_advanced(find_cmd)
|
||||
endif()
|
||||
|
||||
# find command is much quicker than checking every file one by one on Unix
|
||||
# which can take long time for large bundles, and since anyway we expect
|
||||
# executable to have execute flag set we can narrow the list much quicker.
|
||||
if(find_cmd)
|
||||
execute_process(COMMAND "${find_cmd}" "${bundle}"
|
||||
-type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \)
|
||||
OUTPUT_VARIABLE file_list
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REPLACE "\n" ";" file_list "${file_list}")
|
||||
else()
|
||||
file(GLOB_RECURSE file_list "${bundle}/*")
|
||||
endif()
|
||||
|
||||
foreach(f ${file_list})
|
||||
is_file_executable("${f}" is_executable)
|
||||
if(is_executable)
|
||||
set(exes ${exes} "${f}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${exes_var} "${exes}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_item_rpaths item rpaths_var)
|
||||
if(APPLE)
|
||||
find_program(otool_cmd "otool")
|
||||
mark_as_advanced(otool_cmd)
|
||||
endif()
|
||||
|
||||
if(otool_cmd)
|
||||
execute_process(
|
||||
COMMAND "${otool_cmd}" -l "${item}"
|
||||
OUTPUT_VARIABLE load_cmds_ov
|
||||
)
|
||||
string(REGEX REPLACE "[^\n]+cmd LC_RPATH\n[^\n]+\n[^\n]+path ([^\n]+) \\(offset[^\n]+\n" "rpath \\1\n" load_cmds_ov "${load_cmds_ov}")
|
||||
string(REGEX MATCHALL "rpath [^\n]+" load_cmds_ov "${load_cmds_ov}")
|
||||
string(REGEX REPLACE "rpath " "" load_cmds_ov "${load_cmds_ov}")
|
||||
if(load_cmds_ov)
|
||||
gp_append_unique(${rpaths_var} "${load_cmds_ov}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${rpaths_var} ${${rpaths_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_item_key item key_var)
|
||||
get_filename_component(item_name "${item}" NAME)
|
||||
if(WIN32)
|
||||
string(TOLOWER "${item_name}" item_name)
|
||||
endif()
|
||||
string(REPLACE "." "_" ${key_var} "${item_name}")
|
||||
set(${key_var} ${${key_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(clear_bundle_keys keys_var)
|
||||
foreach(key ${${keys_var}})
|
||||
set(${key}_ITEM PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG PARENT_SCOPE)
|
||||
set(${key}_RPATHS PARENT_SCOPE)
|
||||
endforeach()
|
||||
set(${keys_var} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(set_bundle_key_values keys_var context item exepath dirs copyflag)
|
||||
if(ARGC GREATER 6)
|
||||
set(rpaths "${ARGV6}")
|
||||
else()
|
||||
set(rpaths "")
|
||||
endif()
|
||||
get_filename_component(item_name "${item}" NAME)
|
||||
|
||||
get_item_key("${item}" key)
|
||||
|
||||
list(LENGTH ${keys_var} length_before)
|
||||
gp_append_unique(${keys_var} "${key}")
|
||||
list(LENGTH ${keys_var} length_after)
|
||||
|
||||
if(NOT length_before EQUAL length_after)
|
||||
gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item "${rpaths}")
|
||||
|
||||
gp_item_default_embedded_path("${item}" default_embedded_path)
|
||||
|
||||
get_item_rpaths("${resolved_item}" item_rpaths)
|
||||
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
# For frameworks, construct the name under the embedded path from the
|
||||
# opening "${item_name}.framework/" to the closing "/${item_name}":
|
||||
#
|
||||
string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}")
|
||||
else()
|
||||
# For other items, just use the same name as the original, but in the
|
||||
# embedded path:
|
||||
#
|
||||
set(embedded_item "${default_embedded_path}/${item_name}")
|
||||
endif()
|
||||
|
||||
# Replace @executable_path and resolve ".." references:
|
||||
#
|
||||
string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}")
|
||||
get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE)
|
||||
|
||||
# *But* -- if we are not copying, then force resolved_embedded_item to be
|
||||
# the same as resolved_item. In the case of multiple executables in the
|
||||
# original bundle, using the default_embedded_path results in looking for
|
||||
# the resolved executable next to the main bundle executable. This is here
|
||||
# so that exes in the other sibling directories (like "bin") get fixed up
|
||||
# properly...
|
||||
#
|
||||
if(NOT copyflag)
|
||||
set(resolved_embedded_item "${resolved_item}")
|
||||
endif()
|
||||
|
||||
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
|
||||
set(${key}_ITEM "${item}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE)
|
||||
set(${key}_RPATHS "${item_rpaths}" PARENT_SCOPE)
|
||||
set(${key}_RDEP_RPATHS "${rpaths}" PARENT_SCOPE)
|
||||
else()
|
||||
#message("warning: item key '${key}' already in the list, subsequent references assumed identical to first")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_keys app libs dirs keys_var)
|
||||
set(${keys_var} PARENT_SCOPE)
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
if(valid)
|
||||
# Always use the exepath of the main bundle executable for @executable_path
|
||||
# replacements:
|
||||
#
|
||||
get_filename_component(exepath "${executable}" PATH)
|
||||
|
||||
# But do fixups on all executables in the bundle:
|
||||
#
|
||||
get_bundle_all_executables("${bundle}" exes)
|
||||
|
||||
# Set keys for main executable first:
|
||||
#
|
||||
set_bundle_key_values(${keys_var} "${executable}" "${executable}" "${exepath}" "${dirs}" 0)
|
||||
|
||||
# Get rpaths specified by main executable:
|
||||
#
|
||||
get_item_key("${executable}" executable_key)
|
||||
set(main_rpaths "${${executable_key}_RPATHS}")
|
||||
|
||||
# For each extra lib, accumulate a key as well and then also accumulate
|
||||
# any of its prerequisites. (Extra libs are typically dynamically loaded
|
||||
# plugins: libraries that are prerequisites for full runtime functionality
|
||||
# but that do not show up in otool -L output...)
|
||||
#
|
||||
foreach(lib ${libs})
|
||||
set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0 "${main_rpaths}")
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}" "${main_rpaths}")
|
||||
foreach(pr ${prereqs})
|
||||
set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1 "${main_rpaths}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# For each executable found in the bundle, accumulate keys as we go.
|
||||
# The list of keys should be complete when all prerequisites of all
|
||||
# binaries in the bundle have been analyzed.
|
||||
#
|
||||
foreach(exe ${exes})
|
||||
# Main executable is scanned first above:
|
||||
#
|
||||
if(NOT "${exe}" STREQUAL "${executable}")
|
||||
# Add the exe itself to the keys:
|
||||
#
|
||||
set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0 "${main_rpaths}")
|
||||
|
||||
# Get rpaths specified by executable:
|
||||
#
|
||||
get_item_key("${exe}" exe_key)
|
||||
set(exe_rpaths "${main_rpaths}" "${${exe_key}_RPATHS}")
|
||||
else()
|
||||
set(exe_rpaths "${main_rpaths}")
|
||||
endif()
|
||||
|
||||
# Add each prerequisite to the keys:
|
||||
#
|
||||
set(prereqs "")
|
||||
get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}" "${exe_rpaths}")
|
||||
foreach(pr ${prereqs})
|
||||
set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1 "${exe_rpaths}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Propagate values to caller's scope:
|
||||
#
|
||||
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
|
||||
foreach(key ${${keys_var}})
|
||||
set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE)
|
||||
set(${key}_RPATHS "${${key}_RPATHS}" PARENT_SCOPE)
|
||||
set(${key}_RDEP_RPATHS "${${key}_RDEP_RPATHS}" PARENT_SCOPE)
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
if(BU_COPY_FULL_FRAMEWORK_CONTENTS)
|
||||
# Full Framework (everything):
|
||||
get_filename_component(resolved_dir "${resolved_item}" PATH)
|
||||
get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE)
|
||||
get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH)
|
||||
get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE)
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}")
|
||||
else()
|
||||
# Framework lib itself:
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
|
||||
# Plus Resources, if they exist:
|
||||
string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}")
|
||||
string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}")
|
||||
if(EXISTS "${resolved_resources}")
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}")
|
||||
endif()
|
||||
|
||||
# Some frameworks e.g. Qt put Info.plist in wrong place, so when it is
|
||||
# missing in resources, copy it from other well known incorrect locations:
|
||||
if(NOT EXISTS "${resolved_resources}/Info.plist")
|
||||
# Check for Contents/Info.plist in framework root (older Qt SDK):
|
||||
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Contents/Info.plist" resolved_info_plist "${resolved_item}")
|
||||
string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources/Info.plist" resolved_embedded_info_plist "${resolved_embedded_item}")
|
||||
if(EXISTS "${resolved_info_plist}")
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_info_plist}' '${resolved_embedded_info_plist}'")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}" "${resolved_embedded_info_plist}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Check if framework is versioned and fix it layout
|
||||
string(REGEX REPLACE "^.*/([^/]+)/[^/]+$" "\\1" resolved_embedded_version "${resolved_embedded_item}")
|
||||
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions "${resolved_embedded_item}")
|
||||
string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions_basename "${resolved_embedded_item}")
|
||||
if(resolved_embedded_versions_basename STREQUAL "Versions")
|
||||
# Ensure Current symlink points to the framework version
|
||||
if(NOT EXISTS "${resolved_embedded_versions}/Current")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}" "${resolved_embedded_versions}/Current")
|
||||
endif()
|
||||
# Restore symlinks in framework root pointing to current framework
|
||||
# binary and resources:
|
||||
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1" resolved_embedded_root "${resolved_embedded_item}")
|
||||
string(REGEX REPLACE "^.*/([^/]+)$" "\\1" resolved_embedded_item_basename "${resolved_embedded_item}")
|
||||
if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}" "${resolved_embedded_root}/${resolved_embedded_item_basename}")
|
||||
endif()
|
||||
if(NOT EXISTS "${resolved_embedded_root}/Resources")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources" "${resolved_embedded_root}/Resources")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
function(fixup_bundle_item resolved_embedded_item exepath dirs)
|
||||
# This item's key is "ikey":
|
||||
#
|
||||
get_item_key("${resolved_embedded_item}" ikey)
|
||||
|
||||
# Ensure the item is "inside the .app bundle" -- it should not be fixed up if
|
||||
# it is not in the .app bundle... Otherwise, we'll modify files in the build
|
||||
# tree, or in other varied locations around the file system, with our call to
|
||||
# install_name_tool. Make sure that doesn't happen here:
|
||||
#
|
||||
get_dotapp_dir("${exepath}" exe_dotapp_dir)
|
||||
string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length)
|
||||
string(LENGTH "${resolved_embedded_item}" resolved_embedded_item_length)
|
||||
set(path_too_short 0)
|
||||
set(is_embedded 0)
|
||||
if(${resolved_embedded_item_length} LESS ${exe_dotapp_dir_length})
|
||||
set(path_too_short 1)
|
||||
endif()
|
||||
if(NOT path_too_short)
|
||||
string(SUBSTRING "${resolved_embedded_item}" 0 ${exe_dotapp_dir_length} item_substring)
|
||||
if("${exe_dotapp_dir}/" STREQUAL "${item_substring}")
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT is_embedded)
|
||||
message(" exe_dotapp_dir/='${exe_dotapp_dir}/'")
|
||||
message(" item_substring='${item_substring}'")
|
||||
message(" resolved_embedded_item='${resolved_embedded_item}'")
|
||||
message("")
|
||||
message("Install or copy the item into the bundle before calling fixup_bundle.")
|
||||
message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?")
|
||||
message("")
|
||||
message(FATAL_ERROR "cannot fixup an item that is not in the bundle...")
|
||||
endif()
|
||||
|
||||
set(rpaths "${${ikey}_RPATHS}" "${${ikey}_RDEP_RPATHS}")
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}" "${rpaths}")
|
||||
|
||||
set(changes "")
|
||||
|
||||
foreach(pr ${prereqs})
|
||||
# Each referenced item's key is "rkey" in the loop:
|
||||
#
|
||||
get_item_key("${pr}" rkey)
|
||||
|
||||
if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "")
|
||||
set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}")
|
||||
else()
|
||||
message("warning: unexpected reference to '${pr}'")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(BU_CHMOD_BUNDLE_ITEMS)
|
||||
execute_process(COMMAND chmod u+w "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
# Only if install_name_tool supports -delete_rpath:
|
||||
#
|
||||
execute_process(COMMAND install_name_tool
|
||||
OUTPUT_VARIABLE install_name_tool_usage
|
||||
ERROR_VARIABLE install_name_tool_usage
|
||||
)
|
||||
if(install_name_tool_usage MATCHES ".*-delete_rpath.*")
|
||||
foreach(rpath ${${ikey}_RPATHS})
|
||||
set(changes ${changes} -delete_rpath "${rpath}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(${ikey}_EMBEDDED_ITEM)
|
||||
set(changes ${changes} -id "${${ikey}_EMBEDDED_ITEM}")
|
||||
endif()
|
||||
|
||||
# Change this item's id and all of its references in one call
|
||||
# to install_name_tool:
|
||||
#
|
||||
if(changes)
|
||||
set(cmd install_name_tool ${changes} "${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${cmd} RESULT_VARIABLE install_name_tool_result)
|
||||
if(NOT install_name_tool_result EQUAL 0)
|
||||
string(REPLACE ";" "' '" msg "'${cmd}'")
|
||||
message(FATAL_ERROR "Command failed:\n ${msg}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(fixup_bundle app libs dirs)
|
||||
message(STATUS "fixup_bundle")
|
||||
message(STATUS " app='${app}'")
|
||||
message(STATUS " libs='${libs}'")
|
||||
message(STATUS " dirs='${dirs}'")
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
if(valid)
|
||||
get_filename_component(exepath "${executable}" PATH)
|
||||
|
||||
message(STATUS "fixup_bundle: preparing...")
|
||||
get_bundle_keys("${app}" "${libs}" "${dirs}" keys)
|
||||
|
||||
message(STATUS "fixup_bundle: copying...")
|
||||
list(LENGTH keys n)
|
||||
math(EXPR n ${n}*2)
|
||||
|
||||
set(i 0)
|
||||
foreach(key ${keys})
|
||||
math(EXPR i ${i}+1)
|
||||
if(${${key}_COPYFLAG})
|
||||
message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'")
|
||||
else()
|
||||
message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'")
|
||||
endif()
|
||||
|
||||
set(show_status 0)
|
||||
if(show_status)
|
||||
message(STATUS "key='${key}'")
|
||||
message(STATUS "item='${${key}_ITEM}'")
|
||||
message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'")
|
||||
message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'")
|
||||
message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'")
|
||||
message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
message(STATUS "copyflag='${${key}_COPYFLAG}'")
|
||||
message(STATUS "")
|
||||
endif()
|
||||
|
||||
if(${${key}_COPYFLAG})
|
||||
set(item "${${key}_ITEM}")
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}"
|
||||
"${${key}_RESOLVED_EMBEDDED_ITEM}")
|
||||
else()
|
||||
copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}"
|
||||
"${${key}_RESOLVED_EMBEDDED_ITEM}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message(STATUS "fixup_bundle: fixing...")
|
||||
foreach(key ${keys})
|
||||
math(EXPR i ${i}+1)
|
||||
if(APPLE)
|
||||
message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}")
|
||||
else()
|
||||
message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message(STATUS "fixup_bundle: cleaning up...")
|
||||
clear_bundle_keys(keys)
|
||||
|
||||
message(STATUS "fixup_bundle: verifying...")
|
||||
verify_app("${app}")
|
||||
else()
|
||||
message(SEND_ERROR "error: fixup_bundle: not a valid bundle")
|
||||
endif()
|
||||
|
||||
message(STATUS "fixup_bundle: done")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_and_fixup_bundle src dst libs dirs)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}")
|
||||
fixup_bundle("${dst}" "${libs}" "${dirs}")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_bundle_prerequisites bundle result_var info_var)
|
||||
set(result 1)
|
||||
set(info "")
|
||||
set(count 0)
|
||||
|
||||
get_bundle_main_executable("${bundle}" main_bundle_exe)
|
||||
|
||||
get_bundle_all_executables("${bundle}" file_list)
|
||||
foreach(f ${file_list})
|
||||
get_filename_component(exepath "${f}" PATH)
|
||||
math(EXPR count "${count} + 1")
|
||||
|
||||
message(STATUS "executable file ${count}: ${f}")
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${f}" prereqs 1 1 "${exepath}" "")
|
||||
|
||||
# On the Mac,
|
||||
# "embedded" and "system" prerequisites are fine... anything else means
|
||||
# the bundle's prerequisites are not verified (i.e., the bundle is not
|
||||
# really "standalone")
|
||||
#
|
||||
# On Windows (and others? Linux/Unix/...?)
|
||||
# "local" and "system" prereqs are fine...
|
||||
#
|
||||
set(external_prereqs "")
|
||||
|
||||
foreach(p ${prereqs})
|
||||
set(p_type "")
|
||||
gp_file_type("${f}" "${p}" p_type)
|
||||
|
||||
if(APPLE)
|
||||
if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system")
|
||||
set(external_prereqs ${external_prereqs} "${p}")
|
||||
endif()
|
||||
else()
|
||||
if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system")
|
||||
set(external_prereqs ${external_prereqs} "${p}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(external_prereqs)
|
||||
# Found non-system/somehow-unacceptable prerequisites:
|
||||
set(result 0)
|
||||
set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(result)
|
||||
set(info "Verified ${count} executable files in '${bundle}'")
|
||||
endif()
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
set(${info_var} "${info}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_bundle_symlinks bundle result_var info_var)
|
||||
set(result 1)
|
||||
set(info "")
|
||||
set(count 0)
|
||||
|
||||
# TODO: implement this function for real...
|
||||
# Right now, it is just a stub that verifies unconditionally...
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
set(${info_var} "${info}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_app app)
|
||||
set(verified 0)
|
||||
set(info "")
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
|
||||
message(STATUS "===========================================================================")
|
||||
message(STATUS "Analyzing app='${app}'")
|
||||
message(STATUS "bundle='${bundle}'")
|
||||
message(STATUS "executable='${executable}'")
|
||||
message(STATUS "valid='${valid}'")
|
||||
|
||||
# Verify that the bundle does not have any "external" prerequisites:
|
||||
#
|
||||
verify_bundle_prerequisites("${bundle}" verified info)
|
||||
message(STATUS "verified='${verified}'")
|
||||
message(STATUS "info='${info}'")
|
||||
message(STATUS "")
|
||||
|
||||
if(verified)
|
||||
# Verify that the bundle does not have any symlinks to external files:
|
||||
#
|
||||
verify_bundle_symlinks("${bundle}" verified info)
|
||||
message(STATUS "verified='${verified}'")
|
||||
message(STATUS "info='${info}'")
|
||||
message(STATUS "")
|
||||
endif()
|
||||
|
||||
if(NOT verified)
|
||||
message(FATAL_ERROR "error: verify_app failed")
|
||||
endif()
|
||||
endfunction()
|
@ -1,64 +0,0 @@
|
||||
#
|
||||
# Find the hamlib library
|
||||
#
|
||||
# This will define the following variables::
|
||||
#
|
||||
# Hamlib_FOUND - True if the system has the usb library
|
||||
# Hamlib_VERSION - The verion of the usb library which was found
|
||||
#
|
||||
# and the following imported targets::
|
||||
#
|
||||
# Hamlib::Hamlib - The hamlib library
|
||||
#
|
||||
|
||||
include (LibFindMacros)
|
||||
|
||||
libfind_pkg_detect (Hamlib hamlib
|
||||
FIND_PATH hamlib/rig.h PATH_SUFFIXES hamlib
|
||||
FIND_LIBRARY hamlib
|
||||
)
|
||||
|
||||
libfind_package (Hamlib Usb)
|
||||
|
||||
libfind_process (Hamlib)
|
||||
|
||||
if (NOT Hamlib_PKGCONF_FOUND)
|
||||
if (WIN32)
|
||||
set (Hamlib_LIBRARIES ${Hamlib_LIBRARIES};${Usb_LIBRARY};ws2_32)
|
||||
else ()
|
||||
set (Hamlib_LIBRARIES ${Hamlib_LIBRARIES};m;dl)
|
||||
endif ()
|
||||
elseif (UNIX AND NOT APPLE)
|
||||
set (Hamlib_LIBRARIES ${Hamlib_PKGCONF_STATIC_LDFLAGS})
|
||||
endif ()
|
||||
|
||||
# fix up extra link libraries for macOS as target_link_libraries gets
|
||||
# it wrong for frameworks
|
||||
unset (_next_is_framework)
|
||||
unset (_Hamlib_EXTRA_LIBS)
|
||||
foreach (_lib IN LISTS Hamlib_LIBRARIES Hamlib_PKGCONF_LDFLAGS)
|
||||
if (_next_is_framework)
|
||||
list (APPEND _Hamlib_EXTRA_LIBS "-framework ${_lib}")
|
||||
unset (_next_is_framework)
|
||||
elseif (${_lib} STREQUAL "-framework")
|
||||
set (_next_is_framework TRUE)
|
||||
else ()
|
||||
list (APPEND _Hamlib_EXTRA_LIBS ${_lib})
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
if (Hamlib_FOUND AND NOT TARGET Hamlib::Hamlib)
|
||||
add_library (Hamlib::Hamlib UNKNOWN IMPORTED)
|
||||
set_target_properties (Hamlib::Hamlib PROPERTIES
|
||||
IMPORTED_LOCATION "${Hamlib_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${Hamlib_PKGCONF_STATIC_OTHER}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Hamlib_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${_Hamlib_EXTRA_LIBS}"
|
||||
)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced (
|
||||
Hamlib_INCLUDE_DIR
|
||||
Hamlib_LIBRARY
|
||||
Hamlib_LIBRARIES
|
||||
)
|
@ -1,50 +0,0 @@
|
||||
# - Try to find portaudio
|
||||
#
|
||||
# Once done, this will define:
|
||||
#
|
||||
# Portaudio_FOUND - system has portaudio
|
||||
# Portaudio_VERSION - The version of the portaudio library which was found
|
||||
#
|
||||
# and the following imported targets::
|
||||
#
|
||||
# Portaudio::Portaudio - The portaudio library
|
||||
#
|
||||
|
||||
include (LibFindMacros)
|
||||
|
||||
libfind_pkg_detect (Portaudio portaudio-2.0
|
||||
FIND_PATH portaudio.h
|
||||
FIND_LIBRARY portaudio
|
||||
)
|
||||
|
||||
libfind_process (Portaudio)
|
||||
|
||||
# fix up extra link libraries for macOS as target_link_libraries gets
|
||||
# it wrong for frameworks
|
||||
unset (_next_is_framework)
|
||||
unset (_Portaudio_EXTRA_LIBS)
|
||||
foreach (_lib IN LISTS Portaudio_PKGCONF_LDFLAGS)
|
||||
if (_next_is_framework)
|
||||
list (APPEND _Portaudio_EXTRA_LIBS "-framework ${_lib}")
|
||||
unset (_next_is_framework)
|
||||
elseif (${_lib} STREQUAL "-framework")
|
||||
set (_next_is_framework TRUE)
|
||||
else ()
|
||||
list (APPEND _Portaudio_EXTRA_LIBS ${_lib})
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
if (Portaudio_FOUND AND NOT TARGET Portaudio::Portaudio)
|
||||
add_library (Portaudio::Portaudio UNKNOWN IMPORTED)
|
||||
set_target_properties (Portaudio::Portaudio PROPERTIES
|
||||
IMPORTED_LOCATION "${Portaudio_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${Portaudio_PKGCONF_CFLAGS_OTHER}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Portaudio_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES "${_Portaudio_EXTRA_LIBS}"
|
||||
)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced (
|
||||
Portaudio_INCLUDE_DIR
|
||||
Portaudio_LIBRARY
|
||||
)
|
@ -1,49 +0,0 @@
|
||||
# Findlibusb
|
||||
# ==========
|
||||
#
|
||||
# Find the usb library
|
||||
#
|
||||
# This will define the following variables::
|
||||
#
|
||||
# Usb_FOUND - True if the system has the usb library
|
||||
# Usb_VERSION - The verion of the usb library which was found
|
||||
#
|
||||
# and the following imported targets::
|
||||
#
|
||||
# Usb::Usb - The libusb library
|
||||
#
|
||||
|
||||
include (LibFindMacros)
|
||||
|
||||
if (WIN32)
|
||||
# Use path suffixes on MS Windows as we probably shouldn't
|
||||
# trust the PATH envvar. PATH will still be searched to find the
|
||||
# library as last resort.
|
||||
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
set (_library_options PATH_SUFFIXES MinGW64/dll MinGW64/static)
|
||||
else ()
|
||||
set (_library_options PATH_SUFFIXES MinGW32/dll MinGW32/static)
|
||||
endif ()
|
||||
endif ()
|
||||
libfind_pkg_detect (Usb usb-1.0
|
||||
FIND_PATH libusb.h PATH_SUFFIXES libusb-1.0
|
||||
FIND_LIBRARY usb-1.0 ${_library_options}
|
||||
)
|
||||
|
||||
libfind_process (Usb)
|
||||
|
||||
if (Usb_FOUND AND NOT TARGET Usb::Usb)
|
||||
add_library (Usb::Usb UNKNOWN IMPORTED)
|
||||
set_target_properties (Usb::Usb PROPERTIES
|
||||
IMPORTED_LOCATION "${Usb_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${Usb_PKGCONF_CFLAGS_OTHER}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Usb_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES "${Usb_LIBRARIES}"
|
||||
)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced (
|
||||
Usb_INCLUDE_DIR
|
||||
Usb_LIBRARY
|
||||
Usb_LIBRARIES
|
||||
)
|
88
CMake/Modules/Findhamlib.cmake
Normal file
@ -0,0 +1,88 @@
|
||||
# - Try to find hamlib
|
||||
#
|
||||
# Once done, this will define:
|
||||
#
|
||||
# hamlib_FOUND - system has Hamlib
|
||||
# hamlib_INCLUDE_DIRS - the Hamlib include directories
|
||||
# hamlib_LIBRARIES - link these to use Hamlib
|
||||
# hamlib_LIBRARY_DIRS - required shared/dynamic libraries are here
|
||||
#
|
||||
# If hamlib_STATIC is TRUE then static linking will be assumed
|
||||
#
|
||||
|
||||
include (LibFindMacros)
|
||||
|
||||
set (hamlib_LIBRARY_DIRS)
|
||||
|
||||
# pkg-config?
|
||||
find_path (__hamlib_pc_path NAMES hamlib.pc
|
||||
PATH_SUFFIXES lib/pkgconfig lib64/pkgconfig
|
||||
)
|
||||
if (__hamlib_pc_path)
|
||||
set (__pc_path $ENV{PKG_CONFIG_PATH})
|
||||
list (APPEND __pc_path "${__hamlib_pc_path}")
|
||||
set (ENV{PKG_CONFIG_PATH} "${__pc_path}")
|
||||
unset (__pc_path CACHE)
|
||||
endif ()
|
||||
unset (__hamlib_pc_path CACHE)
|
||||
|
||||
# Use pkg-config to get hints about paths, libs and, flags
|
||||
unset (__pkg_config_checked_hamlib CACHE)
|
||||
# pkg_config will fail on Windows if the Hamlib USB backends are
|
||||
# configured since libusb-1.0 does not ship with a pkg_config file on
|
||||
# Windows, that's OK because we fix it up below
|
||||
libfind_pkg_check_modules (PC_HAMLIB hamlib)
|
||||
|
||||
if (NOT PC_HAMLIB_FOUND)
|
||||
# The headers
|
||||
find_path (hamlib_INCLUDEDIR hamlib/rig.h)
|
||||
# The libraries
|
||||
if (hamlib_STATIC)
|
||||
libfind_library (hamlib libhamlib.a)
|
||||
else ()
|
||||
libfind_library (hamlib hamlib)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
set (hamlib_EXTRA_LIBRARIES ws2_32)
|
||||
else ()
|
||||
set (hamlib_EXTRA_LIBRARIES m dl)
|
||||
endif ()
|
||||
|
||||
# libusb-1.0 has no pkg-config file on Windows so we have to find it
|
||||
# ourselves
|
||||
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
find_library (LIBUSB NAMES usb-1.0 PATH_SUFFIXES MinGW64/dll)
|
||||
else ()
|
||||
find_library (LIBUSB NAMES usb-1.0 PATH_SUFFIXES MinGW32/dll)
|
||||
endif ()
|
||||
if (LIBUSB)
|
||||
set (hamlib_EXTRA_LIBRARIES ${LIBUSB} ${hamlib_EXTRA_LIBRARIES})
|
||||
get_filename_component (hamlib_libusb_path ${LIBUSB} PATH)
|
||||
set (hamlib_LIBRARY_DIRS ${hamlib_LIBRARY_DIRS} ${hamlib_libusb_path})
|
||||
endif (LIBUSB)
|
||||
set (hamlib_PROCESS_INCLUDES hamlib_INCLUDEDIR)
|
||||
set (hamlib_PROCESS_LIBS hamlib_LIBRARY hamlib_EXTRA_LIBRARIES)
|
||||
else ()
|
||||
if (hamlib_STATIC)
|
||||
set (hamlib_PROCESS_INCLUDES PC_HAMLIB_STATIC_INCLUDE_DIRS)
|
||||
set (hamlib_PROCESS_LIBS PC_HAMLIB_STATIC_LDFLAGS)
|
||||
set (hamlib_LIBRARY_DIRS ${PC_HAMLIB_STATIC_LIBRARY_DIRS})
|
||||
else ()
|
||||
set (hamlib_PROCESS_INCLUDES PC_HAMLIB_INCLUDE_DIRS)
|
||||
set (hamlib_PROCESS_LIBS PC_HAMLIB_LDFLAGS)
|
||||
set (hamlib_LIBRARY_DIRS ${PC_HAMLIB_LIBRARY_DIRS})
|
||||
endif ()
|
||||
endif ()
|
||||
libfind_process (hamlib)
|
||||
|
||||
if (WIN32)
|
||||
find_path (hamlib_dll_path libhamlib-2.dll)
|
||||
if (hamlib_dll_path)
|
||||
set (hamlib_LIBRARY_DIRS ${hamlib_LIBRARY_DIRS} ${hamlib_dll_path})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to
|
||||
# TRUE if all listed variables are TRUE
|
||||
include (FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES hamlib_LIBRARY_DIRS)
|
998
CMake/Modules/GetPrerequisites.cmake
Normal file
@ -0,0 +1,998 @@
|
||||
#.rst:
|
||||
# GetPrerequisites
|
||||
# ----------------
|
||||
#
|
||||
# Functions to analyze and list executable file prerequisites.
|
||||
#
|
||||
# This module provides functions to list the .dll, .dylib or .so files
|
||||
# that an executable or shared library file depends on. (Its
|
||||
# prerequisites.)
|
||||
#
|
||||
# It uses various tools to obtain the list of required shared library
|
||||
# files:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# dumpbin (Windows)
|
||||
# objdump (MinGW on Windows)
|
||||
# ldd (Linux/Unix)
|
||||
# otool (Mac OSX)
|
||||
#
|
||||
# The following functions are provided by this module:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# get_prerequisites
|
||||
# list_prerequisites
|
||||
# list_prerequisites_by_glob
|
||||
# gp_append_unique
|
||||
# is_file_executable
|
||||
# gp_item_default_embedded_path
|
||||
# (projects can override with gp_item_default_embedded_path_override)
|
||||
# gp_resolve_item
|
||||
# (projects can override with gp_resolve_item_override)
|
||||
# gp_resolved_file_type
|
||||
# (projects can override with gp_resolved_file_type_override)
|
||||
# gp_file_type
|
||||
#
|
||||
# Requires CMake 2.6 or greater because it uses function, break, return
|
||||
# and PARENT_SCOPE.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
|
||||
# <exepath> <dirs> [<rpaths>])
|
||||
#
|
||||
# Get the list of shared library files required by <target>. The list
|
||||
# in the variable named <prerequisites_var> should be empty on first
|
||||
# entry to this function. On exit, <prerequisites_var> will contain the
|
||||
# list of required shared library files.
|
||||
#
|
||||
# <target> is the full path to an executable file. <prerequisites_var>
|
||||
# is the name of a CMake variable to contain the results.
|
||||
# <exclude_system> must be 0 or 1 indicating whether to include or
|
||||
# exclude "system" prerequisites. If <recurse> is set to 1 all
|
||||
# prerequisites will be found recursively, if set to 0 only direct
|
||||
# prerequisites are listed. <exepath> is the path to the top level
|
||||
# executable used for @executable_path replacment on the Mac. <dirs> is
|
||||
# a list of paths where libraries might be found: these paths are
|
||||
# searched first when a target without any path info is given. Then
|
||||
# standard system locations are also searched: PATH, Framework
|
||||
# locations, /usr/lib...
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
|
||||
#
|
||||
# Print a message listing the prerequisites of <target>.
|
||||
#
|
||||
# <target> is the name of a shared library or executable target or the
|
||||
# full path to a shared library or executable file. If <recurse> is set
|
||||
# to 1 all prerequisites will be found recursively, if set to 0 only
|
||||
# direct prerequisites are listed. <exclude_system> must be 0 or 1
|
||||
# indicating whether to include or exclude "system" prerequisites. With
|
||||
# <verbose> set to 0 only the full path names of the prerequisites are
|
||||
# printed, set to 1 extra informatin will be displayed.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
|
||||
#
|
||||
# Print the prerequisites of shared library and executable files
|
||||
# matching a globbing pattern. <glob_arg> is GLOB or GLOB_RECURSE and
|
||||
# <glob_exp> is a globbing expression used with "file(GLOB" or
|
||||
# "file(GLOB_RECURSE" to retrieve a list of matching files. If a
|
||||
# matching file is executable, its prerequisites are listed.
|
||||
#
|
||||
# Any additional (optional) arguments provided are passed along as the
|
||||
# optional arguments to the list_prerequisites calls.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GP_APPEND_UNIQUE(<list_var> <value>)
|
||||
#
|
||||
# Append <value> to the list variable <list_var> only if the value is
|
||||
# not already in the list.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# IS_FILE_EXECUTABLE(<file> <result_var>)
|
||||
#
|
||||
# Return 1 in <result_var> if <file> is a binary executable, 0
|
||||
# otherwise.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
|
||||
#
|
||||
# Return the path that others should refer to the item by when the item
|
||||
# is embedded inside a bundle.
|
||||
#
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_item_default_embedded_path_override function.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>
|
||||
# [<rpaths>])
|
||||
#
|
||||
# Resolve an item into an existing full path file.
|
||||
#
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_resolve_item_override function.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>
|
||||
# [<rpaths>])
|
||||
#
|
||||
# Return the type of <file> with respect to <original_file>. String
|
||||
# describing type of prerequisite is returned in variable named
|
||||
# <type_var>.
|
||||
#
|
||||
# Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
|
||||
# values -- but only for non-embedded items.
|
||||
#
|
||||
# Possible types are:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# system
|
||||
# local
|
||||
# embedded
|
||||
# other
|
||||
#
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_resolved_file_type_override function.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# GP_FILE_TYPE(<original_file> <file> <type_var>)
|
||||
#
|
||||
# Return the type of <file> with respect to <original_file>. String
|
||||
# describing type of prerequisite is returned in variable named
|
||||
# <type_var>.
|
||||
#
|
||||
# Possible types are:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# system
|
||||
# local
|
||||
# embedded
|
||||
# other
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2008-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function(gp_append_unique list_var value)
|
||||
set(contains 0)
|
||||
|
||||
foreach(item ${${list_var}})
|
||||
if(item STREQUAL "${value}")
|
||||
set(contains 1)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT contains)
|
||||
set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(is_file_executable file result_var)
|
||||
#
|
||||
# A file is not executable until proven otherwise:
|
||||
#
|
||||
set(${result_var} 0 PARENT_SCOPE)
|
||||
|
||||
get_filename_component(file_full "${file}" ABSOLUTE)
|
||||
string(TOLOWER "${file_full}" file_full_lower)
|
||||
|
||||
# If file name ends in .exe on Windows, *assume* executable:
|
||||
#
|
||||
if(WIN32 AND NOT UNIX)
|
||||
if("${file_full_lower}" MATCHES "\\.exe$")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# A clause could be added here that uses output or return value of dumpbin
|
||||
# to determine ${result_var}. In 99%+? practical cases, the exe name
|
||||
# match will be sufficient...
|
||||
#
|
||||
endif()
|
||||
|
||||
# Use the information returned from the Unix shell command "file" to
|
||||
# determine if ${file_full} should be considered an executable file...
|
||||
#
|
||||
# If the file command's output contains "executable" and does *not* contain
|
||||
# "text" then it is likely an executable suitable for prerequisite analysis
|
||||
# via the get_prerequisites macro.
|
||||
#
|
||||
if(UNIX)
|
||||
if(NOT file_cmd)
|
||||
find_program(file_cmd "file")
|
||||
mark_as_advanced(file_cmd)
|
||||
endif()
|
||||
|
||||
if(file_cmd)
|
||||
execute_process(COMMAND "${file_cmd}" "${file_full}"
|
||||
RESULT_VARIABLE file_rv
|
||||
OUTPUT_VARIABLE file_ov
|
||||
ERROR_VARIABLE file_ev
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT file_rv STREQUAL "0")
|
||||
message(FATAL_ERROR "${file_cmd} failed: ${file_rv}\n${file_ev}")
|
||||
endif()
|
||||
|
||||
# Replace the name of the file in the output with a placeholder token
|
||||
# (the string " _file_full_ ") so that just in case the path name of
|
||||
# the file contains the word "text" or "executable" we are not fooled
|
||||
# into thinking "the wrong thing" because the file name matches the
|
||||
# other 'file' command output we are looking for...
|
||||
#
|
||||
string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
|
||||
string(TOLOWER "${file_ov}" file_ov)
|
||||
|
||||
#message(STATUS "file_ov='${file_ov}'")
|
||||
if("${file_ov}" MATCHES "executable")
|
||||
#message(STATUS "executable!")
|
||||
if("${file_ov}" MATCHES "text")
|
||||
#message(STATUS "but text, so *not* a binary executable!")
|
||||
else()
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Also detect position independent executables on Linux,
|
||||
# where "file" gives "shared object ... (uses shared libraries)"
|
||||
if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# "file" version 5.22 does not print "(used shared libraries)"
|
||||
# but uses "interpreter"
|
||||
if("${file_ov}" MATCHES "shared object.*interpreter")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
else()
|
||||
message(STATUS "warning: No 'file' command, skipping execute_process...")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_item_default_embedded_path item default_embedded_path_var)
|
||||
|
||||
# On Windows and Linux, "embed" prerequisites in the same directory
|
||||
# as the executable by default:
|
||||
#
|
||||
set(path "@executable_path")
|
||||
set(overridden 0)
|
||||
|
||||
# On the Mac, relative to the executable depending on the type
|
||||
# of the thing we are embedding:
|
||||
#
|
||||
if(APPLE)
|
||||
#
|
||||
# The assumption here is that all executables in the bundle will be
|
||||
# in same-level-directories inside the bundle. The parent directory
|
||||
# of an executable inside the bundle should be MacOS or a sibling of
|
||||
# MacOS and all embedded paths returned from here will begin with
|
||||
# "@executable_path/../" and will work from all executables in all
|
||||
# such same-level-directories inside the bundle.
|
||||
#
|
||||
|
||||
# By default, embed things right next to the main bundle executable:
|
||||
#
|
||||
set(path "@executable_path/../../Contents/MacOS")
|
||||
|
||||
# Embed .dylibs right next to the main bundle executable:
|
||||
#
|
||||
if(item MATCHES "\\.dylib$")
|
||||
set(path "@executable_path/../MacOS")
|
||||
set(overridden 1)
|
||||
endif()
|
||||
|
||||
# Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
|
||||
#
|
||||
if(NOT overridden)
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
set(path "@executable_path/../Frameworks")
|
||||
set(overridden 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override the default embedded location
|
||||
# of any given library by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_item_default_embedded_path_override)
|
||||
gp_item_default_embedded_path_override("${item}" path)
|
||||
endif()
|
||||
|
||||
set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_resolve_item context item exepath dirs resolved_item_var)
|
||||
set(resolved 0)
|
||||
set(resolved_item "${item}")
|
||||
if(ARGC GREATER 5)
|
||||
set(rpaths "${ARGV5}")
|
||||
else()
|
||||
set(rpaths "")
|
||||
endif()
|
||||
|
||||
# Is it already resolved?
|
||||
#
|
||||
if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
|
||||
set(resolved 1)
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "^@executable_path")
|
||||
#
|
||||
# @executable_path references are assumed relative to exepath
|
||||
#
|
||||
string(REPLACE "@executable_path" "${exepath}" ri "${item}")
|
||||
get_filename_component(ri "${ri}" ABSOLUTE)
|
||||
|
||||
if(EXISTS "${ri}")
|
||||
#message(STATUS "info: embedded item exists (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
else()
|
||||
message(STATUS "warning: embedded item does not exist '${ri}'")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "^@loader_path")
|
||||
#
|
||||
# @loader_path references are assumed relative to the
|
||||
# PATH of the given "context" (presumably another library)
|
||||
#
|
||||
get_filename_component(contextpath "${context}" PATH)
|
||||
string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
|
||||
get_filename_component(ri "${ri}" ABSOLUTE)
|
||||
|
||||
if(EXISTS "${ri}")
|
||||
#message(STATUS "info: embedded item exists (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
else()
|
||||
message(STATUS "warning: embedded item does not exist '${ri}'")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "^@rpath")
|
||||
#
|
||||
# @rpath references are relative to the paths built into the binaries with -rpath
|
||||
# We handle this case like we do for other Unixes
|
||||
#
|
||||
string(REPLACE "@rpath/" "" norpath_item "${item}")
|
||||
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_file(ri "${norpath_item}" ${exepath} ${dirs} ${rpaths} NO_DEFAULT_PATH)
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_file' in exepath/dirs/rpaths (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
|
||||
find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
set(fw "fw-NOTFOUND")
|
||||
find_file(fw "${item}"
|
||||
"~/Library/Frameworks"
|
||||
"/Library/Frameworks"
|
||||
"/System/Library/Frameworks"
|
||||
)
|
||||
if(fw)
|
||||
#message(STATUS "info: 'find_file' found framework (${fw})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${fw}")
|
||||
set(fw "fw-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Using find_program on Windows will find dll files that are in the PATH.
|
||||
# (Converting simple file names into full path names if found.)
|
||||
#
|
||||
if(WIN32 AND NOT UNIX)
|
||||
if(NOT resolved)
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
|
||||
find_program(ri "${item}" PATHS "${exepath};${dirs}")
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override item resolution
|
||||
# by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_resolve_item_override)
|
||||
gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
message(STATUS "
|
||||
warning: cannot resolve item '${item}'
|
||||
|
||||
possible problems:
|
||||
need more directories?
|
||||
need to use InstallRequiredSystemLibraries?
|
||||
run in install tree instead of build tree?
|
||||
")
|
||||
# message(STATUS "
|
||||
#******************************************************************************
|
||||
#warning: cannot resolve item '${item}'
|
||||
#
|
||||
# possible problems:
|
||||
# need more directories?
|
||||
# need to use InstallRequiredSystemLibraries?
|
||||
# run in install tree instead of build tree?
|
||||
#
|
||||
# context='${context}'
|
||||
# item='${item}'
|
||||
# exepath='${exepath}'
|
||||
# dirs='${dirs}'
|
||||
# resolved_item_var='${resolved_item_var}'
|
||||
#******************************************************************************
|
||||
#")
|
||||
endif()
|
||||
|
||||
set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_resolved_file_type original_file file exepath dirs type_var)
|
||||
if(ARGC GREATER 5)
|
||||
set(rpaths "${ARGV5}")
|
||||
else()
|
||||
set(rpaths "")
|
||||
endif()
|
||||
#message(STATUS "**")
|
||||
|
||||
if(NOT IS_ABSOLUTE "${original_file}")
|
||||
message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
|
||||
endif()
|
||||
|
||||
set(is_embedded 0)
|
||||
set(is_local 0)
|
||||
set(is_system 0)
|
||||
|
||||
set(resolved_file "${file}")
|
||||
|
||||
if("${file}" MATCHES "^@(executable|loader)_path")
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
|
||||
if(NOT is_embedded)
|
||||
if(NOT IS_ABSOLUTE "${file}")
|
||||
gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file "${rpaths}")
|
||||
endif()
|
||||
|
||||
string(TOLOWER "${original_file}" original_lower)
|
||||
string(TOLOWER "${resolved_file}" lower)
|
||||
|
||||
if(UNIX)
|
||||
if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
string(TOLOWER "$ENV{SystemRoot}" sysroot)
|
||||
file(TO_CMAKE_PATH "${sysroot}" sysroot)
|
||||
|
||||
string(TOLOWER "$ENV{windir}" windir)
|
||||
file(TO_CMAKE_PATH "${windir}" windir)
|
||||
|
||||
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
# if cygwin, we can get the properly formed windows paths from cygpath
|
||||
find_program(CYGPATH_EXECUTABLE cygpath)
|
||||
|
||||
if(CYGPATH_EXECUTABLE)
|
||||
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
|
||||
RESULT_VARIABLE env_rv
|
||||
OUTPUT_VARIABLE env_windir
|
||||
ERROR_VARIABLE env_ev
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT env_rv STREQUAL "0")
|
||||
message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -W failed: ${env_rv}\n${env_ev}")
|
||||
endif()
|
||||
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
|
||||
RESULT_VARIABLE env_rv
|
||||
OUTPUT_VARIABLE env_sysdir
|
||||
ERROR_VARIABLE env_ev
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT env_rv STREQUAL "0")
|
||||
message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -S failed: ${env_rv}\n${env_ev}")
|
||||
endif()
|
||||
string(TOLOWER "${env_windir}" windir)
|
||||
string(TOLOWER "${env_sysdir}" sysroot)
|
||||
|
||||
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT is_system)
|
||||
get_filename_component(original_path "${original_lower}" PATH)
|
||||
get_filename_component(path "${lower}" PATH)
|
||||
if(original_path STREQUAL path)
|
||||
set(is_local 1)
|
||||
else()
|
||||
string(LENGTH "${original_path}/" original_length)
|
||||
string(LENGTH "${lower}" path_length)
|
||||
if(${path_length} GREATER ${original_length})
|
||||
string(SUBSTRING "${lower}" 0 ${original_length} path)
|
||||
if("${original_path}/" STREQUAL path)
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Return type string based on computed booleans:
|
||||
#
|
||||
set(type "other")
|
||||
|
||||
if(is_system)
|
||||
set(type "system")
|
||||
elseif(is_embedded)
|
||||
set(type "embedded")
|
||||
elseif(is_local)
|
||||
set(type "local")
|
||||
endif()
|
||||
|
||||
#message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
|
||||
#message(STATUS " type: '${type}'")
|
||||
|
||||
if(NOT is_embedded)
|
||||
if(NOT IS_ABSOLUTE "${resolved_file}")
|
||||
if(lower MATCHES "^msvc[^/]+dll" AND is_system)
|
||||
message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
|
||||
else()
|
||||
message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override the decision on whether a
|
||||
# library belongs to the system or not by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_resolved_file_type_override)
|
||||
gp_resolved_file_type_override("${resolved_file}" type)
|
||||
endif()
|
||||
|
||||
set(${type_var} "${type}" PARENT_SCOPE)
|
||||
|
||||
#message(STATUS "**")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_file_type original_file file type_var)
|
||||
if(NOT IS_ABSOLUTE "${original_file}")
|
||||
message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
|
||||
endif()
|
||||
|
||||
get_filename_component(exepath "${original_file}" PATH)
|
||||
|
||||
set(type "")
|
||||
gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
|
||||
|
||||
set(${type_var} "${type}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
|
||||
set(verbose 0)
|
||||
set(eol_char "E")
|
||||
if(ARGC GREATER 6)
|
||||
set(rpaths "${ARGV6}")
|
||||
else()
|
||||
set(rpaths "")
|
||||
endif()
|
||||
|
||||
if(NOT IS_ABSOLUTE "${target}")
|
||||
message("warning: target '${target}' is not absolute...")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${target}")
|
||||
message("warning: target '${target}' does not exist...")
|
||||
endif()
|
||||
|
||||
set(gp_cmd_paths ${gp_cmd_paths}
|
||||
"C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
|
||||
"C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
|
||||
"C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
|
||||
"/usr/local/bin"
|
||||
"/usr/bin"
|
||||
)
|
||||
|
||||
# <setup-gp_tool-vars>
|
||||
#
|
||||
# Try to choose the right tool by default. Caller can set gp_tool prior to
|
||||
# calling this function to force using a different tool.
|
||||
#
|
||||
if(NOT gp_tool)
|
||||
set(gp_tool "ldd")
|
||||
|
||||
if(APPLE)
|
||||
set(gp_tool "otool")
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har!
|
||||
find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths})
|
||||
if(gp_dumpbin)
|
||||
set(gp_tool "dumpbin")
|
||||
else() # Try harder. Maybe we're on MinGW
|
||||
set(gp_tool "objdump")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
|
||||
|
||||
if(NOT gp_cmd)
|
||||
message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(gp_cmd_maybe_filter) # optional command to pre-filter gp_tool results
|
||||
|
||||
if(gp_tool STREQUAL "ldd")
|
||||
set(gp_cmd_args "")
|
||||
set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$")
|
||||
set(gp_regex_error "not found${eol_char}$")
|
||||
set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$")
|
||||
set(gp_regex_cmp_count 1)
|
||||
elseif(gp_tool STREQUAL "otool")
|
||||
set(gp_cmd_args "-L")
|
||||
set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 3)
|
||||
elseif(gp_tool STREQUAL "dumpbin")
|
||||
set(gp_cmd_args "/dependents")
|
||||
set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 1)
|
||||
elseif(gp_tool STREQUAL "objdump")
|
||||
set(gp_cmd_args "-p")
|
||||
set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 1)
|
||||
# objdump generaates copious output so we create a grep filter to pre-filter results
|
||||
find_program(gp_grep_cmd grep)
|
||||
if(gp_grep_cmd)
|
||||
set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "^[[:blank:]]*DLL Name: ")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
|
||||
message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
|
||||
message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
if(gp_tool STREQUAL "dumpbin")
|
||||
# When running dumpbin, it also needs the "Common7/IDE" directory in the
|
||||
# PATH. It will already be in the PATH if being run from a Visual Studio
|
||||
# command prompt. Add it to the PATH here in case we are running from a
|
||||
# different command prompt.
|
||||
#
|
||||
get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
|
||||
get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
|
||||
# Use cmake paths as a user may have a PATH element ending with a backslash.
|
||||
# This will escape the list delimiter and create havoc!
|
||||
if(EXISTS "${gp_cmd_dlls_dir}")
|
||||
# only add to the path if it is not already in the path
|
||||
set(gp_found_cmd_dlls_dir 0)
|
||||
file(TO_CMAKE_PATH "$ENV{PATH}" env_path)
|
||||
foreach(gp_env_path_element ${env_path})
|
||||
if(gp_env_path_element STREQUAL gp_cmd_dlls_dir)
|
||||
set(gp_found_cmd_dlls_dir 1)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT gp_found_cmd_dlls_dir)
|
||||
file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir)
|
||||
set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
#
|
||||
# </setup-gp_tool-vars>
|
||||
|
||||
if(gp_tool STREQUAL "ldd")
|
||||
set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
|
||||
set(new_ld_env "${exepath}")
|
||||
foreach(dir ${dirs})
|
||||
set(new_ld_env "${new_ld_env}:${dir}")
|
||||
endforeach()
|
||||
set(ENV{LD_LIBRARY_PATH} "${new_ld_env}:$ENV{LD_LIBRARY_PATH}")
|
||||
endif()
|
||||
|
||||
|
||||
# Track new prerequisites at each new level of recursion. Start with an
|
||||
# empty list at each level:
|
||||
#
|
||||
set(unseen_prereqs)
|
||||
|
||||
# Run gp_cmd on the target:
|
||||
#
|
||||
execute_process(
|
||||
COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
|
||||
${gp_cmd_maybe_filter}
|
||||
RESULT_VARIABLE gp_rv
|
||||
OUTPUT_VARIABLE gp_cmd_ov
|
||||
ERROR_VARIABLE gp_ev
|
||||
)
|
||||
if(NOT gp_rv STREQUAL "0")
|
||||
if(gp_tool STREQUAL "dumpbin")
|
||||
# dumpbin error messages seem to go to stdout
|
||||
message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}\n${gp_cmd_ov}")
|
||||
else()
|
||||
message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(gp_tool STREQUAL "ldd")
|
||||
set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
|
||||
endif()
|
||||
|
||||
if(verbose)
|
||||
message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
|
||||
message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
|
||||
message(STATUS "</RawOutput>")
|
||||
endif()
|
||||
|
||||
get_filename_component(target_dir "${target}" PATH)
|
||||
|
||||
# Convert to a list of lines:
|
||||
#
|
||||
string(REPLACE ";" "\\;" candidates "${gp_cmd_ov}")
|
||||
string(REPLACE "\n" "${eol_char};" candidates "${candidates}")
|
||||
|
||||
# check for install id and remove it from list, since otool -L can include a
|
||||
# reference to itself
|
||||
set(gp_install_id)
|
||||
if(gp_tool STREQUAL "otool")
|
||||
execute_process(
|
||||
COMMAND otool -D ${target}
|
||||
RESULT_VARIABLE otool_rv
|
||||
OUTPUT_VARIABLE gp_install_id_ov
|
||||
ERROR_VARIABLE otool_ev
|
||||
)
|
||||
if(NOT otool_rv STREQUAL "0")
|
||||
message(FATAL_ERROR "otool -D failed: ${otool_rv}\n${otool_ev}")
|
||||
endif()
|
||||
# second line is install name
|
||||
string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
|
||||
if(gp_install_id)
|
||||
# trim
|
||||
string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}")
|
||||
#message("INSTALL ID is \"${gp_install_id}\"")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Analyze each line for file names that match the regular expression:
|
||||
#
|
||||
foreach(candidate ${candidates})
|
||||
if("${candidate}" MATCHES "${gp_regex}")
|
||||
|
||||
# Extract information from each candidate:
|
||||
if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}")
|
||||
string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}")
|
||||
else()
|
||||
string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
|
||||
endif()
|
||||
|
||||
if(gp_regex_cmp_count GREATER 1)
|
||||
string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
|
||||
endif()
|
||||
|
||||
if(gp_regex_cmp_count GREATER 2)
|
||||
string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
|
||||
endif()
|
||||
|
||||
# Use the raw_item as the list entries returned by this function. Use the
|
||||
# gp_resolve_item function to resolve it to an actual full path file if
|
||||
# necessary.
|
||||
#
|
||||
set(item "${raw_item}")
|
||||
|
||||
# Add each item unless it is excluded:
|
||||
#
|
||||
set(add_item 1)
|
||||
|
||||
if(item STREQUAL gp_install_id)
|
||||
set(add_item 0)
|
||||
endif()
|
||||
|
||||
if(add_item AND ${exclude_system})
|
||||
set(type "")
|
||||
gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type "${rpaths}")
|
||||
|
||||
if(type STREQUAL "system")
|
||||
set(add_item 0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(add_item)
|
||||
list(LENGTH ${prerequisites_var} list_length_before_append)
|
||||
gp_append_unique(${prerequisites_var} "${item}")
|
||||
list(LENGTH ${prerequisites_var} list_length_after_append)
|
||||
|
||||
if(${recurse})
|
||||
# If item was really added, this is the first time we have seen it.
|
||||
# Add it to unseen_prereqs so that we can recursively add *its*
|
||||
# prerequisites...
|
||||
#
|
||||
# But first: resolve its name to an absolute full path name such
|
||||
# that the analysis tools can simply accept it as input.
|
||||
#
|
||||
if(NOT list_length_before_append EQUAL list_length_after_append)
|
||||
gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item "${rpaths}")
|
||||
set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(verbose)
|
||||
message(STATUS "ignoring non-matching line: '${candidate}'")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(LENGTH ${prerequisites_var} prerequisites_var_length)
|
||||
if(prerequisites_var_length GREATER 0)
|
||||
list(SORT ${prerequisites_var})
|
||||
endif()
|
||||
if(${recurse})
|
||||
set(more_inputs ${unseen_prereqs})
|
||||
foreach(input ${more_inputs})
|
||||
get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}" "${rpaths}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(list_prerequisites target)
|
||||
if(ARGC GREATER 1 AND NOT "${ARGV1}" STREQUAL "")
|
||||
set(all "${ARGV1}")
|
||||
else()
|
||||
set(all 1)
|
||||
endif()
|
||||
|
||||
if(ARGC GREATER 2 AND NOT "${ARGV2}" STREQUAL "")
|
||||
set(exclude_system "${ARGV2}")
|
||||
else()
|
||||
set(exclude_system 0)
|
||||
endif()
|
||||
|
||||
if(ARGC GREATER 3 AND NOT "${ARGV3}" STREQUAL "")
|
||||
set(verbose "${ARGV3}")
|
||||
else()
|
||||
set(verbose 0)
|
||||
endif()
|
||||
|
||||
set(count 0)
|
||||
set(count_str "")
|
||||
set(print_count "${verbose}")
|
||||
set(print_prerequisite_type "${verbose}")
|
||||
set(print_target "${verbose}")
|
||||
set(type_str "")
|
||||
|
||||
get_filename_component(exepath "${target}" PATH)
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
|
||||
|
||||
if(print_target)
|
||||
message(STATUS "File '${target}' depends on:")
|
||||
endif()
|
||||
|
||||
foreach(d ${prereqs})
|
||||
math(EXPR count "${count} + 1")
|
||||
|
||||
if(print_count)
|
||||
set(count_str "${count}. ")
|
||||
endif()
|
||||
|
||||
if(print_prerequisite_type)
|
||||
gp_file_type("${target}" "${d}" type)
|
||||
set(type_str " (${type})")
|
||||
endif()
|
||||
|
||||
message(STATUS "${count_str}${d}${type_str}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(list_prerequisites_by_glob glob_arg glob_exp)
|
||||
message(STATUS "=============================================================================")
|
||||
message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
|
||||
message(STATUS "")
|
||||
file(${glob_arg} file_list ${glob_exp})
|
||||
foreach(f ${file_list})
|
||||
is_file_executable("${f}" is_f_executable)
|
||||
if(is_f_executable)
|
||||
message(STATUS "=============================================================================")
|
||||
list_prerequisites("${f}" ${ARGN})
|
||||
message(STATUS "")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
@ -1,101 +1,46 @@
|
||||
# Version 2.3
|
||||
# Public Domain, originally written by Lasse Kärkkäinen <tronic>
|
||||
# Maintained at https://github.com/Tronic/cmake-modules
|
||||
# Please send your improvements as pull requests on Github.
|
||||
# Version 1.0 (2013-04-12)
|
||||
# Public Domain, originally written by Lasse Kärkkäinen <tronic@zi.fi>
|
||||
# Published at http://www.cmake.org/Wiki/CMake:How_To_Find_Libraries
|
||||
|
||||
# Find another package and make it a dependency of the current package.
|
||||
# This also automatically forwards the "REQUIRED" argument.
|
||||
# Usage: libfind_package(<prefix> <another package> [extra args to find_package])
|
||||
macro (libfind_package PREFIX PKG)
|
||||
set(${PREFIX}_args ${PKG} ${ARGN})
|
||||
# If you improve the script, please modify the forementioned wiki page because
|
||||
# I no longer maintain my scripts (hosted as static files at zi.fi). Feel free
|
||||
# to remove this entire header if you use real version control instead.
|
||||
|
||||
# Changelog:
|
||||
# 2013-04-12 Added version number (1.0) and this header, no other changes
|
||||
# 2009-10-08 Originally published
|
||||
|
||||
|
||||
# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
|
||||
# used for the current package. For this to work, the first parameter must be the
|
||||
# prefix of the current package, then the prefix of the new package etc, which are
|
||||
# passed to find_package.
|
||||
macro (libfind_package PREFIX)
|
||||
set (LIBFIND_PACKAGE_ARGS ${ARGN})
|
||||
if (${PREFIX}_FIND_QUIETLY)
|
||||
set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
|
||||
endif (${PREFIX}_FIND_QUIETLY)
|
||||
if (${PREFIX}_FIND_REQUIRED)
|
||||
set(${PREFIX}_args ${${PREFIX}_args} REQUIRED)
|
||||
endif()
|
||||
find_package(${${PREFIX}_args})
|
||||
set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG})
|
||||
unset(${PREFIX}_args)
|
||||
endmacro()
|
||||
set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
|
||||
endif (${PREFIX}_FIND_REQUIRED)
|
||||
find_package(${LIBFIND_PACKAGE_ARGS})
|
||||
endmacro (libfind_package)
|
||||
|
||||
# A simple wrapper to make pkg-config searches a bit easier.
|
||||
# Works the same as CMake's internal pkg_check_modules but is always quiet.
|
||||
macro (libfind_pkg_check_modules)
|
||||
find_package(PkgConfig QUIET)
|
||||
# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
|
||||
# where they added pkg_check_modules. Consequently I need to support both in my scripts
|
||||
# to avoid those deprecated warnings. Here's a helper that does just that.
|
||||
# Works identically to pkg_check_modules, except that no checks are needed prior to use.
|
||||
macro (libfind_pkg_check_modules PREFIX PKGNAME)
|
||||
if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
include(UsePkgConfig)
|
||||
pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
|
||||
else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
find_package(PkgConfig)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(${ARGN} QUIET)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Avoid useless copy&pasta by doing what most simple libraries do anyway:
|
||||
# pkg-config, find headers, find library.
|
||||
# Usage: libfind_pkg_detect(<prefix> <pkg-config args> FIND_PATH <name> [other args] FIND_LIBRARY <name> [other args])
|
||||
# E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2)
|
||||
function (libfind_pkg_detect PREFIX)
|
||||
# Parse arguments
|
||||
set(argname pkgargs)
|
||||
foreach (i ${ARGN})
|
||||
if ("${i}" STREQUAL "FIND_PATH")
|
||||
set(argname pathargs)
|
||||
elseif ("${i}" STREQUAL "FIND_LIBRARY")
|
||||
set(argname libraryargs)
|
||||
else()
|
||||
set(${argname} ${${argname}} ${i})
|
||||
endif()
|
||||
endforeach()
|
||||
if (NOT pkgargs)
|
||||
message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.")
|
||||
endif()
|
||||
# Find library
|
||||
libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs})
|
||||
if (pathargs)
|
||||
find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS})
|
||||
endif()
|
||||
if (libraryargs)
|
||||
find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS})
|
||||
endif()
|
||||
# Read pkg-config version
|
||||
if (${PREFIX}_PKGCONF_VERSION)
|
||||
set(${PREFIX}_VERSION ${${PREFIX}_PKGCONF_VERSION} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Extracts a version #define from a version.h file, output stored to <PREFIX>_VERSION.
|
||||
# Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR)
|
||||
# Fourth argument "QUIET" may be used for silently testing different define names.
|
||||
# This function does nothing if the version variable is already defined.
|
||||
function (libfind_version_header PREFIX VERSION_H DEFINE_NAME)
|
||||
# Skip processing if we already have a version or if the include dir was not found
|
||||
if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR)
|
||||
return()
|
||||
endif()
|
||||
set(quiet ${${PREFIX}_FIND_QUIETLY})
|
||||
# Process optional arguments
|
||||
foreach(arg ${ARGN})
|
||||
if (arg STREQUAL "QUIET")
|
||||
set(quiet TRUE)
|
||||
else()
|
||||
message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.")
|
||||
endif()
|
||||
endforeach()
|
||||
# Read the header and parse for version number
|
||||
set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
|
||||
if (NOT EXISTS ${filename})
|
||||
if (NOT quiet)
|
||||
message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
file(READ "${filename}" header)
|
||||
string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}")
|
||||
# No regex match?
|
||||
if (match STREQUAL header)
|
||||
if (NOT quiet)
|
||||
message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"<version>\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
# Export the version string
|
||||
set(${PREFIX}_VERSION "${match}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
pkg_check_modules(${PREFIX} ${PKGNAME})
|
||||
endif (PKG_CONFIG_FOUND)
|
||||
endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
endmacro (libfind_pkg_check_modules)
|
||||
|
||||
# Do the final processing once the paths have been detected.
|
||||
# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
|
||||
@ -103,167 +48,65 @@ endfunction()
|
||||
# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
|
||||
# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
|
||||
# Also handles errors in case library detection was required, etc.
|
||||
function (libfind_process PREFIX)
|
||||
# Skip processing if already processed during this configuration run
|
||||
if (${PREFIX}_FOUND)
|
||||
return()
|
||||
endif()
|
||||
macro (libfind_process PREFIX)
|
||||
# Skip processing if already processed during this run
|
||||
if (NOT ${PREFIX}_FOUND)
|
||||
# Start with the assumption that the library was found
|
||||
set (${PREFIX}_FOUND TRUE)
|
||||
|
||||
set(found TRUE) # Start with the assumption that the package was found
|
||||
|
||||
# Did we find any files? Did we miss includes? These are for formatting better error messages.
|
||||
set(some_files FALSE)
|
||||
set(missing_headers FALSE)
|
||||
|
||||
# Shorthands for some variables that we need often
|
||||
set(quiet ${${PREFIX}_FIND_QUIETLY})
|
||||
set(required ${${PREFIX}_FIND_REQUIRED})
|
||||
set(exactver ${${PREFIX}_FIND_VERSION_EXACT})
|
||||
set(findver "${${PREFIX}_FIND_VERSION}")
|
||||
set(version "${${PREFIX}_VERSION}")
|
||||
|
||||
# Lists of config option names (all, includes, libs)
|
||||
unset(configopts)
|
||||
set(includeopts ${${PREFIX}_PROCESS_INCLUDES})
|
||||
set(libraryopts ${${PREFIX}_PROCESS_LIBS})
|
||||
|
||||
# Process deps to add to
|
||||
foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES})
|
||||
if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS)
|
||||
# The package seems to export option lists that we can use, woohoo!
|
||||
list(APPEND includeopts ${${i}_INCLUDE_OPTS})
|
||||
list(APPEND libraryopts ${${i}_LIBRARY_OPTS})
|
||||
else()
|
||||
# If plural forms don't exist or they equal singular forms
|
||||
if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR
|
||||
(${i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES))
|
||||
# Singular forms can be used
|
||||
if (DEFINED ${i}_INCLUDE_DIR)
|
||||
list(APPEND includeopts ${i}_INCLUDE_DIR)
|
||||
endif()
|
||||
if (DEFINED ${i}_LIBRARY)
|
||||
list(APPEND libraryopts ${i}_LIBRARY)
|
||||
endif()
|
||||
else()
|
||||
# Oh no, we don't know the option names
|
||||
message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (includeopts)
|
||||
list(REMOVE_DUPLICATES includeopts)
|
||||
endif()
|
||||
|
||||
if (libraryopts)
|
||||
list(REMOVE_DUPLICATES libraryopts)
|
||||
endif()
|
||||
|
||||
string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}")
|
||||
if (NOT tmp STREQUAL "${includeopts} ${libraryopts}")
|
||||
message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).")
|
||||
endif()
|
||||
|
||||
# Include/library names separated by spaces (notice: not CMake lists)
|
||||
unset(includes)
|
||||
unset(libs)
|
||||
|
||||
# Process all includes and set found false if any are missing
|
||||
foreach (i ${includeopts})
|
||||
list(APPEND configopts ${i})
|
||||
if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
|
||||
list(APPEND includes "${${i}}")
|
||||
else()
|
||||
set(found FALSE)
|
||||
set(missing_headers TRUE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Process all libraries and set found false if any are missing
|
||||
foreach (i ${libraryopts})
|
||||
list(APPEND configopts ${i})
|
||||
if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
|
||||
list(APPEND libs "${${i}}")
|
||||
else()
|
||||
set (found FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Version checks
|
||||
if (found AND findver)
|
||||
if (NOT version)
|
||||
message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.")
|
||||
elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver))
|
||||
set(found FALSE)
|
||||
set(version_unsuitable TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# If all-OK, hide all config options, export variables, print status and exit
|
||||
if (found)
|
||||
foreach (i ${configopts})
|
||||
# Process all includes and set _FOUND to false if any are missing
|
||||
foreach (i ${${PREFIX}_PROCESS_INCLUDES})
|
||||
if (${i})
|
||||
set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
|
||||
mark_as_advanced(${i})
|
||||
endforeach()
|
||||
if (NOT quiet)
|
||||
message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
|
||||
if (LIBFIND_DEBUG)
|
||||
message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}")
|
||||
message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}")
|
||||
message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}")
|
||||
message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}")
|
||||
message(STATUS " ${PREFIX}_LIBRARIES=${libs}")
|
||||
endif()
|
||||
endif()
|
||||
set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE)
|
||||
set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE)
|
||||
set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE)
|
||||
set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE)
|
||||
set (${PREFIX}_FOUND TRUE PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
else (${i})
|
||||
set (${PREFIX}_FOUND FALSE)
|
||||
endif (${i})
|
||||
endforeach (i)
|
||||
|
||||
# Format messages for debug info and the type of error
|
||||
set(vars "Relevant CMake configuration variables:\n")
|
||||
foreach (i ${configopts})
|
||||
mark_as_advanced(CLEAR ${i})
|
||||
set(val ${${i}})
|
||||
if ("${val}" STREQUAL "${i}-NOTFOUND")
|
||||
set (val "<not found>")
|
||||
elseif (val AND NOT EXISTS ${val})
|
||||
set (val "${val} (does not exist)")
|
||||
else()
|
||||
set(some_files TRUE)
|
||||
endif()
|
||||
set(vars "${vars} ${i}=${val}\n")
|
||||
endforeach()
|
||||
set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n")
|
||||
if (version_unsuitable)
|
||||
set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but")
|
||||
if (exactver)
|
||||
set(msg "${msg} only version ${findver} is acceptable.")
|
||||
else()
|
||||
set(msg "${msg} version ${findver} is the minimum requirement.")
|
||||
endif()
|
||||
else()
|
||||
if (missing_headers)
|
||||
set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?")
|
||||
elseif (some_files)
|
||||
set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?")
|
||||
if(findver)
|
||||
set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).")
|
||||
endif()
|
||||
else()
|
||||
set(msg "We were unable to find package ${PREFIX}.")
|
||||
endif()
|
||||
endif()
|
||||
# Process all libraries and set _FOUND to false if any are missing
|
||||
foreach (i ${${PREFIX}_PROCESS_LIBS})
|
||||
if (${i})
|
||||
set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
|
||||
mark_as_advanced(${i})
|
||||
else (${i})
|
||||
set (${PREFIX}_FOUND FALSE)
|
||||
endif (${i})
|
||||
endforeach (i)
|
||||
|
||||
# Print message and/or exit on fatal error
|
||||
if (${PREFIX}_FOUND)
|
||||
if (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
|
||||
endif (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
else (${PREFIX}_FOUND)
|
||||
if (${PREFIX}_FIND_REQUIRED)
|
||||
foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
|
||||
message("${i}=${${i}}")
|
||||
endforeach (i)
|
||||
message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
|
||||
endif (${PREFIX}_FIND_REQUIRED)
|
||||
endif (${PREFIX}_FOUND)
|
||||
endif (NOT ${PREFIX}_FOUND)
|
||||
endmacro (libfind_process)
|
||||
|
||||
macro(libfind_library PREFIX basename)
|
||||
set(TMP "")
|
||||
if(MSVC80)
|
||||
set(TMP -vc80)
|
||||
endif(MSVC80)
|
||||
if(MSVC90)
|
||||
set(TMP -vc90)
|
||||
endif(MSVC90)
|
||||
set(${PREFIX}_LIBNAMES ${basename}${TMP})
|
||||
if(${ARGC} GREATER 2)
|
||||
set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
|
||||
string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
|
||||
set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
|
||||
endif(${ARGC} GREATER 2)
|
||||
find_library(${PREFIX}_LIBRARY
|
||||
NAMES ${${PREFIX}_LIBNAMES}
|
||||
PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
|
||||
)
|
||||
endmacro(libfind_library)
|
||||
|
||||
# Fatal error out if REQUIRED
|
||||
if (required)
|
||||
set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.")
|
||||
message(FATAL_ERROR "${msg}\n${vars}")
|
||||
endif()
|
||||
# Otherwise just print a nasty warning
|
||||
if (NOT quiet)
|
||||
message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
@ -26,7 +26,7 @@ if (WIN32)
|
||||
add_custom_command (
|
||||
OUTPUT ${outfile}.h ${outfile}.cpp
|
||||
COMMAND ${DUMPCPP_Executable}
|
||||
ARGS ${ax_server_options} -o "${outfile}" "${infile}"
|
||||
ARGS ${AX_SERVER_options} -o "${outfile}" "${infile}"
|
||||
MAIN_DEPENDENCY ${infile} VERBATIM)
|
||||
list (APPEND ${outfiles} ${outfile}.cpp)
|
||||
endforeach()
|
||||
|
311
CMakeLists.txt
@ -45,7 +45,7 @@ if (POLICY CMP0075)
|
||||
endif ()
|
||||
|
||||
project (wsjtx
|
||||
VERSION 2.7.0.0
|
||||
VERSION 2.4.0.0
|
||||
LANGUAGES C CXX Fortran
|
||||
)
|
||||
set (PROJECT_DESCRIPTION "WSJT-X: Digital Modes for Weak Signal Communications in Amateur Radio")
|
||||
@ -71,7 +71,7 @@ message (STATUS "******************************************************")
|
||||
|
||||
include (set_build_type)
|
||||
# RC 0 or omitted is a development build, GA is a General Availability release build
|
||||
set_build_type (RC 4)
|
||||
set_build_type (RC 2)
|
||||
set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}")
|
||||
|
||||
#
|
||||
@ -80,10 +80,10 @@ set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_
|
||||
set (PROJECT_BUNDLE_NAME "WSJT-X")
|
||||
set (PROJECT_VENDOR "Joe Taylor, K1JT")
|
||||
set (PROJECT_CONTACT "Joe Taylor <k1jt@arrl.net>")
|
||||
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2023 by Joe Taylor, K1JT")
|
||||
set (PROJECT_HOMEPAGE https://wsjt.sourceforge.io/wsjtx.html)
|
||||
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2021 by Joe Taylor, K1JT")
|
||||
set (PROJECT_HOMEPAGE https://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html)
|
||||
set (PROJECT_MANUAL wsjtx-main)
|
||||
set (PROJECT_MANUAL_DIRECTORY_URL https://wsjt.sourceforge.io/wsjtx-doc/)
|
||||
set (PROJECT_MANUAL_DIRECTORY_URL https://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/)
|
||||
set (PROJECT_SAMPLES_URL http://downloads.sourceforge.net/project/wsjt/)
|
||||
set (PROJECT_SAMPLES_UPLOAD_DEST frs.sourceforge.net:/home/frs/project/wsjt/)
|
||||
|
||||
@ -126,8 +126,7 @@ option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
||||
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
|
||||
option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
|
||||
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_QDEBUG_IN_RELEASE "Leave Qt debugging statements in Release configuration." OFF
|
||||
"NOT is_debug_build" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_ENABLE_EXPERIMENTAL_FEATURES "Enable features not fully ready for public releases." ON
|
||||
is_debug_build OFF)
|
||||
CMAKE_DEPENDENT_OPTION (WSJT_CREATE_WINMAIN
|
||||
@ -161,6 +160,7 @@ endif ()
|
||||
set (WSJT_PLUGIN_DESTINATION ${PLUGIN_DESTINATION} CACHE PATH "Path for plugins")
|
||||
set (WSJT_QT_CONF_DESTINATION ${QT_CONF_DESTINATION} CACHE PATH "Path for the qt.conf file")
|
||||
|
||||
|
||||
#
|
||||
# Project sources
|
||||
#
|
||||
@ -169,7 +169,6 @@ set (fort_qt_CXXSRCS
|
||||
)
|
||||
|
||||
set (wsjt_qt_CXXSRCS
|
||||
helper_functions.cpp
|
||||
qt_helpers.cpp
|
||||
widgets/MessageBox.cpp
|
||||
MetaDataRegistry.cpp
|
||||
@ -189,7 +188,6 @@ set (wsjt_qt_CXXSRCS
|
||||
widgets/FrequencyDeltaLineEdit.cpp
|
||||
item_delegates/CandidateKeyFilter.cpp
|
||||
item_delegates/ForeignKeyDelegate.cpp
|
||||
item_delegates/MessageItemDelegate.cpp
|
||||
validators/LiveFrequencyValidator.cpp
|
||||
GetUserId.cpp
|
||||
Audio/AudioDevice.cpp
|
||||
@ -221,7 +219,6 @@ set (wsjt_qt_CXXSRCS
|
||||
widgets/DoubleClickablePushButton.cpp
|
||||
widgets/DoubleClickableRadioButton.cpp
|
||||
Network/LotWUsers.cpp
|
||||
Network/FileDownload.cpp
|
||||
models/DecodeHighlightingModel.cpp
|
||||
widgets/DecodeHighlightingListView.cpp
|
||||
models/FoxLog.cpp
|
||||
@ -240,7 +237,6 @@ set (wsjt_qt_CXXSRCS
|
||||
Network/NetworkAccessManager.cpp
|
||||
widgets/LazyFillComboBox.cpp
|
||||
widgets/CheckableItemComboBox.cpp
|
||||
widgets/BandComboBox.cpp
|
||||
)
|
||||
|
||||
set (wsjt_qtmm_CXXSRCS
|
||||
@ -275,7 +271,6 @@ set (wsjtx_CXXSRCS
|
||||
widgets/about.cpp
|
||||
widgets/astro.cpp
|
||||
widgets/messageaveraging.cpp
|
||||
widgets/activeStations.cpp
|
||||
widgets/colorhighlighting.cpp
|
||||
WSPR/WsprTxScheduler.cpp
|
||||
widgets/mainwindow.cpp
|
||||
@ -327,7 +322,6 @@ set (wsjt_FSRCS
|
||||
lib/ft8_decode.f90
|
||||
lib/ft4_decode.f90
|
||||
lib/fst4_decode.f90
|
||||
lib/get_q3list.f90
|
||||
lib/jt9_decode.f90
|
||||
lib/options.f90
|
||||
lib/packjt.f90
|
||||
@ -339,8 +333,6 @@ set (wsjt_FSRCS
|
||||
lib/timer_impl.f90
|
||||
lib/timer_module.f90
|
||||
lib/wavhdr.f90
|
||||
lib/qra/q65/q65_encoding_modules.f90
|
||||
lib/ft8/ft8_a7.f90
|
||||
|
||||
# remaining non-module sources
|
||||
lib/addit.f90
|
||||
@ -362,7 +354,6 @@ set (wsjt_FSRCS
|
||||
lib/bpdecode128_90.f90
|
||||
lib/ft8/bpdecode174_91.f90
|
||||
lib/baddata.f90
|
||||
lib/cablog.f90
|
||||
lib/calibrate.f90
|
||||
lib/ccf2.f90
|
||||
lib/ccf65.f90
|
||||
@ -388,8 +379,6 @@ set (wsjt_FSRCS
|
||||
lib/demod64a.f90
|
||||
lib/determ.f90
|
||||
lib/downsam9.f90
|
||||
lib/echosim.f90
|
||||
lib/echo_snr.f90
|
||||
lib/encode232.f90
|
||||
lib/encode4.f90
|
||||
lib/encode_msk40.f90
|
||||
@ -423,7 +412,6 @@ set (wsjt_FSRCS
|
||||
lib/fmtmsg.f90
|
||||
lib/foldspec9f.f90
|
||||
lib/four2a.f90
|
||||
lib/fspread_lorentz.f90
|
||||
lib/ft8/foxfilt.f90
|
||||
lib/ft8/foxgen.f90
|
||||
lib/ft8/foxgen_wrap.f90
|
||||
@ -469,11 +457,11 @@ set (wsjt_FSRCS
|
||||
lib/inter_wspr.f90
|
||||
lib/jplsubs.f
|
||||
lib/jt9fano.f90
|
||||
lib/jtmsg.f90
|
||||
lib/libration.f90
|
||||
lib/lorentzian.f90
|
||||
lib/fst4/lorentzian_fading.f90
|
||||
lib/lpf1.f90
|
||||
lib/map65_mmdec.f90
|
||||
lib/mixlpf.f90
|
||||
lib/makepings.f90
|
||||
lib/moondopjpl.f90
|
||||
@ -492,7 +480,6 @@ set (wsjt_FSRCS
|
||||
lib/msk144sim.f90
|
||||
lib/mskrtd.f90
|
||||
lib/nuttal_window.f90
|
||||
lib/decode_msk144.f90
|
||||
lib/ft4/ft4sim.f90
|
||||
lib/ft4/ft4sim_mult.f90
|
||||
lib/ft4/ft4_downsample.f90
|
||||
@ -512,11 +499,8 @@ set (wsjt_FSRCS
|
||||
lib/qra/q65/q65_ap.f90
|
||||
lib/qra/q65/q65_loops.f90
|
||||
lib/qra/q65/q65_set_list.f90
|
||||
lib/qra/q65/q65_set_list2.f90
|
||||
lib/refspectrum.f90
|
||||
lib/savec2.f90
|
||||
lib/save_dxbase.f90
|
||||
lib/save_echo_params.f90
|
||||
lib/sec0.f90
|
||||
lib/sec_midn.f90
|
||||
lib/setup65.f90
|
||||
@ -542,6 +526,7 @@ set (wsjt_FSRCS
|
||||
lib/symspec2.f90
|
||||
lib/symspec65.f90
|
||||
lib/sync4.f90
|
||||
lib/sync64.f90
|
||||
lib/sync65.f90
|
||||
lib/ft4/getcandidates4.f90
|
||||
lib/ft4/get_ft4_bitmetrics.f90
|
||||
@ -551,7 +536,6 @@ set (wsjt_FSRCS
|
||||
lib/sync9.f90
|
||||
lib/sync9f.f90
|
||||
lib/sync9w.f90
|
||||
lib/test_snr.f90
|
||||
lib/timf2.f90
|
||||
lib/tweak1.f90
|
||||
lib/twkfreq.f90
|
||||
@ -584,7 +568,6 @@ set (wsjt_FSRCS
|
||||
lib/fst4/fastosd240_74.f90
|
||||
lib/fst4/get_crc24.f90
|
||||
lib/fst4/fst4_baseline.f90
|
||||
lib/77bit/hash22calc.f90
|
||||
)
|
||||
|
||||
# temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit
|
||||
@ -663,7 +646,6 @@ set (wsjtx_UISRCS
|
||||
widgets/echograph.ui
|
||||
widgets/fastgraph.ui
|
||||
widgets/messageaveraging.ui
|
||||
widgets/activeStations.ui
|
||||
widgets/widegraph.ui
|
||||
widgets/logqso.ui
|
||||
Configuration.ui
|
||||
@ -832,27 +814,12 @@ endif (APPLE)
|
||||
#
|
||||
include (CheckTypeSize)
|
||||
include (CheckCSourceCompiles)
|
||||
include (CheckIncludeFiles)
|
||||
include (CheckSymbolExists)
|
||||
include (generate_version_info)
|
||||
|
||||
find_program(CTAGS ctags)
|
||||
find_program(ETAGS etags)
|
||||
|
||||
#
|
||||
# Platform checks
|
||||
#
|
||||
check_include_files ("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
|
||||
check_include_files (stdio.h HAVE_STDIO_H)
|
||||
check_include_files (stdlib.h HAVE_STDLIB_H)
|
||||
check_include_files (unistd.h HAVE_UNISTD_H)
|
||||
check_include_files (sys/ioctl.h HAVE_SYS_IOCTL_H)
|
||||
check_include_files (sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_files (fcntl.h HAVE_FCNTL_H)
|
||||
check_include_files (sys/stat.h HAVE_SYS_STAT_H)
|
||||
check_include_files ("linux/ppdev.h;linux/parport.h" HAVE_LINUX_PPDEV_H)
|
||||
check_include_files ("dev/ppbus/ppi.h;dev/ppbus/ppbconf.h" HAVE_DEV_PPBUS_PPI_H)
|
||||
|
||||
#
|
||||
# Standard C Math Library
|
||||
#
|
||||
@ -889,17 +856,24 @@ find_package (OpenMP)
|
||||
find_package (FFTW3 COMPONENTS single threads REQUIRED)
|
||||
|
||||
#
|
||||
# hamlib setup
|
||||
# libhamlib setup
|
||||
#
|
||||
find_package (Hamlib REQUIRED)
|
||||
set (hamlib_STATIC 1)
|
||||
find_package (hamlib 3 REQUIRED)
|
||||
find_program (RIGCTL_EXE rigctl)
|
||||
find_program (RIGCTLD_EXE rigctld)
|
||||
find_program (RIGCTLCOM_EXE rigctlcom)
|
||||
|
||||
message (STATUS "hamlib_INCLUDE_DIRS: ${hamlib_INCLUDE_DIRS}")
|
||||
message (STATUS "hamlib_LIBRARIES: ${hamlib_LIBRARIES}")
|
||||
message (STATUS "hamlib_LIBRARY_DIRS: ${hamlib_LIBRARY_DIRS}")
|
||||
|
||||
set (CMAKE_REQUIRED_INCLUDES "${hamlib_INCLUDE_DIRS}")
|
||||
set (CMAKE_REQUIRED_LIBRARIES "${hamlib_LIBRARIES}")
|
||||
set (CMAKE_EXTRA_INCLUDE_FILES "hamlib/rig.h")
|
||||
check_type_size (CACHE_ALL HAMLIB_OLD_CACHING)
|
||||
check_symbol_exists (rig_set_cache_timeout_ms "hamlib/rig.h" HAVE_HAMLIB_CACHING)
|
||||
|
||||
find_package (Usb REQUIRED)
|
||||
|
||||
#
|
||||
# Qt5 setup
|
||||
@ -913,6 +887,19 @@ if (WIN32)
|
||||
find_package (Qt5AxContainer REQUIRED)
|
||||
endif (WIN32)
|
||||
|
||||
#
|
||||
# sub-directories
|
||||
#
|
||||
if (EXISTS ${CMAKE_SOURCE_DIR}/samples AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/samples)
|
||||
add_subdirectory (samples)
|
||||
endif ()
|
||||
if (WSJT_GENERATE_DOCS)
|
||||
add_subdirectory (doc)
|
||||
endif (WSJT_GENERATE_DOCS)
|
||||
if (EXISTS ${CMAKE_SOURCE_DIR}/tests AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/tests)
|
||||
add_subdirectory (tests)
|
||||
endif ()
|
||||
|
||||
#
|
||||
# Library building setup
|
||||
#
|
||||
@ -975,18 +962,8 @@ if (Fortran_COMPILER_NAME MATCHES "gfortran.*")
|
||||
set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -isysroot ${CMAKE_OSX_SYSROOT}")
|
||||
endif (CMAKE_OSX_SYSROOT)
|
||||
|
||||
set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -fbounds-check -funroll-all-loops -fno-f2c -ffpe-summary=invalid,zero,overflow,underflow ${General_FFLAGS}")
|
||||
|
||||
### TEMPORARY: Let Fortran use RElEASE flags for DEBUG builds
|
||||
#set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -g -fbacktrace -fbounds-check -fno-f2c -ffpe-summary=invalid,zero,overflow,underflow ${General_FFLAGS}")
|
||||
set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_RELEASE} -fbounds-check -funroll-all-loops -fno-f2c -ffpe-summary=invalid,zero,overflow,underflow ${General_FFLAGS}")
|
||||
|
||||
|
||||
# FPE traps currently disabled in Debug configuration builds until
|
||||
# we decide if they are meaningful, without these FP instructions
|
||||
# run in nonstop mode and do not trap
|
||||
#set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_DEBUG} -ffpe-trap=invalid,zero,overflow")
|
||||
|
||||
set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -fbounds-check -funroll-all-loops -fno-f2c ${General_FFLAGS}")
|
||||
set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fbounds-check -fno-f2c ${General_FFLAGS}")
|
||||
elseif (Fortran_COMPILER_NAME MATCHES "ifort.*")
|
||||
# ifort (untested)
|
||||
set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -f77rtl ${General_FFLAGS}")
|
||||
@ -1088,19 +1065,6 @@ elseif (CMAKE_HOST_WIN32)
|
||||
add_definitions (-DWIN32)
|
||||
endif ()
|
||||
|
||||
#
|
||||
# sub-directories
|
||||
#
|
||||
if (EXISTS ${CMAKE_SOURCE_DIR}/samples AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/samples)
|
||||
add_subdirectory (samples)
|
||||
endif ()
|
||||
if (WSJT_GENERATE_DOCS)
|
||||
add_subdirectory (doc)
|
||||
endif (WSJT_GENERATE_DOCS)
|
||||
if (EXISTS ${CMAKE_SOURCE_DIR}/tests AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/tests)
|
||||
add_subdirectory (tests)
|
||||
endif ()
|
||||
|
||||
# build a library of package functionality (without and optionally with OpenMP support)
|
||||
add_library (wsjt_cxx STATIC ${wsjt_CSRCS} ${wsjt_CXXSRCS})
|
||||
target_link_libraries (wsjt_cxx ${LIBM_LIBRARIES} Boost::log_setup ${LIBM_LIBRARIES})
|
||||
@ -1111,7 +1075,7 @@ target_link_libraries (wsjt_fort ${FFTW3_LIBRARIES})
|
||||
if (${OPENMP_FOUND} OR APPLE)
|
||||
add_library (wsjt_fort_omp STATIC ${wsjt_FSRCS})
|
||||
target_link_libraries (wsjt_fort_omp ${FFTW3_LIBRARIES})
|
||||
if (OpenMP_C_FLAGS AND NOT APPLE)
|
||||
if (OpenMP_C_FLAGS)
|
||||
set_target_properties (wsjt_fort_omp
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||
@ -1144,18 +1108,9 @@ target_link_libraries (jt65sim wsjt_fort wsjt_cxx)
|
||||
add_executable (sumsim lib/sumsim.f90)
|
||||
target_link_libraries (sumsim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (cablog lib/cablog.f90)
|
||||
target_link_libraries (cablog)
|
||||
|
||||
add_executable (test_snr lib/test_snr.f90)
|
||||
target_link_libraries (test_snr wsjt_fort)
|
||||
|
||||
add_executable (q65sim lib/qra/q65/q65sim.f90)
|
||||
target_link_libraries (q65sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (q65code lib/qra/q65/q65code.f90)
|
||||
target_link_libraries (q65code wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (test_q65 lib/test_q65.f90)
|
||||
target_link_libraries (test_q65 wsjt_fort wsjt_cxx)
|
||||
|
||||
@ -1183,9 +1138,6 @@ target_link_libraries (wsprcode wsjt_fort wsjt_cxx)
|
||||
add_executable (encode77 lib/77bit/encode77.f90)
|
||||
target_link_libraries (encode77 wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (hash22calc lib/77bit/hash22calc.f90)
|
||||
target_link_libraries (hash22calc wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (wsprsim ${wsprsim_CSRCS})
|
||||
target_link_libraries (wsprsim ${LIBM_LIBRARIES})
|
||||
|
||||
@ -1201,9 +1153,6 @@ target_link_libraries (ft8code wsjt_fort wsjt_cxx)
|
||||
add_executable (ft4code lib/ft4/ft4code.f90)
|
||||
target_link_libraries (ft4code wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (echosim lib/echosim.f90)
|
||||
target_link_libraries (echosim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (ft8sim lib/ft8/ft8sim.f90)
|
||||
target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
|
||||
|
||||
@ -1288,11 +1237,9 @@ set (LANGUAGES
|
||||
ja # Japanese
|
||||
#no # Norwegian
|
||||
#pt # Portuguese
|
||||
ru # Russian
|
||||
#sv # Swedish
|
||||
zh # Chinese
|
||||
zh_HK # Chinese per Hong Kong
|
||||
zh_TW # Chinese traditional
|
||||
it # Italian
|
||||
)
|
||||
foreach (lang_ ${LANGUAGES})
|
||||
@ -1371,7 +1318,8 @@ target_link_libraries (qcp Qt5::Widgets Qt5::PrintSupport)
|
||||
add_library (wsjt_qt STATIC ${wsjt_qt_CXXSRCS} ${wsjt_qt_GENUISRCS} ${GENAXSRCS})
|
||||
# set wsjtx_udp exports to static variants
|
||||
target_compile_definitions (wsjt_qt PUBLIC UDP_STATIC_DEFINE)
|
||||
target_link_libraries (wsjt_qt Hamlib::Hamlib Boost::log qcp Qt5::Widgets Qt5::Network Qt5::Sql)
|
||||
target_link_libraries (wsjt_qt Boost::log qcp Qt5::Widgets Qt5::Network Qt5::Sql)
|
||||
target_include_directories (wsjt_qt BEFORE PRIVATE ${hamlib_INCLUDE_DIRS})
|
||||
if (WIN32)
|
||||
target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase)
|
||||
endif (WIN32)
|
||||
@ -1433,12 +1381,6 @@ else (${OPENMP_FOUND} OR APPLE)
|
||||
target_link_libraries (jt9 wsjt_fort wsjt_cxx fort_qt)
|
||||
endif (${OPENMP_FOUND} OR APPLE)
|
||||
|
||||
if (WIN32)
|
||||
find_package (Portaudio REQUIRED)
|
||||
add_subdirectory (map65)
|
||||
endif ()
|
||||
add_subdirectory (qmap)
|
||||
|
||||
# build the main application
|
||||
generate_version_info (wsjtx_VERSION_RESOURCES
|
||||
NAME wsjtx
|
||||
@ -1472,7 +1414,7 @@ set_target_properties (wsjtx PROPERTIES
|
||||
)
|
||||
|
||||
target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||
if ((NOT ${OPENMP_FOUND}) OR APPLE)
|
||||
if (APPLE)
|
||||
target_link_libraries (wsjtx wsjt_fort)
|
||||
else ()
|
||||
target_link_libraries (wsjtx wsjt_fort_omp)
|
||||
@ -1491,7 +1433,7 @@ else ()
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
target_link_libraries (wsjtx Qt5::SerialPort wsjt_cxx wsjt_qt wsjt_qtmm ${FFTW3_LIBRARIES} ${LIBM_LIBRARIES})
|
||||
target_link_libraries (wsjtx Qt5::SerialPort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES} ${LIBM_LIBRARIES})
|
||||
|
||||
# make a library for WSJT-X UDP servers
|
||||
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
|
||||
@ -1602,8 +1544,7 @@ install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
||||
)
|
||||
|
||||
if(WSJT_BUILD_UTILS)
|
||||
install (TARGETS ft8code jt65code jt9code jt4code msk144code
|
||||
q65code fst4sim q65sim echosim hash22calc cablog
|
||||
install (TARGETS ft8code jt65code jt9code jt4code msk144code fst4sim q65sim
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
@ -1645,7 +1586,6 @@ install (FILES
|
||||
cty.dat
|
||||
cty.dat_copyright.txt
|
||||
contrib/Ephemeris/JPLEPH
|
||||
eclipse.txt
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}
|
||||
#COMPONENT runtime
|
||||
)
|
||||
@ -1663,7 +1603,7 @@ install (DIRECTORY
|
||||
if (APPLE)
|
||||
install (FILES
|
||||
Darwin/ReadMe.txt
|
||||
Darwin/com.wsjtx.sysctl.plist
|
||||
Darwin/sysctl.conf
|
||||
DESTINATION .
|
||||
#COMPONENT runtime
|
||||
)
|
||||
@ -1724,7 +1664,17 @@ if (NOT WIN32 AND NOT APPLE)
|
||||
)
|
||||
endif (NOT WIN32 AND NOT APPLE)
|
||||
|
||||
if (APPLE)
|
||||
|
||||
#
|
||||
# bundle fixup only done in non-Debug configurations
|
||||
#
|
||||
if (NOT is_debug_build)
|
||||
|
||||
get_target_property (QtCore_location Qt5::Core LOCATION)
|
||||
get_filename_component (QtCore_location ${QtCore_location} PATH)
|
||||
list (APPEND fixup_library_dirs ${QtCore_location})
|
||||
|
||||
if (APPLE)
|
||||
set (CMAKE_POSTFLIGHT_SCRIPT
|
||||
"${wsjtx_BINARY_DIR}/postflight.sh")
|
||||
set (CMAKE_POSTUPGRADE_SCRIPT
|
||||
@ -1733,18 +1683,155 @@ if (APPLE)
|
||||
"${CMAKE_POSTFLIGHT_SCRIPT}")
|
||||
configure_file ("${wsjtx_SOURCE_DIR}/Darwin/postupgrade.sh.in"
|
||||
"${CMAKE_POSTUPGRADE_SCRIPT}")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (APPLE OR WIN32)
|
||||
# install rules for including 3rd party libs such as Qt
|
||||
|
||||
#
|
||||
# bundle fixup only done in non-Debug configurations
|
||||
#
|
||||
if (NOT is_debug_build)
|
||||
# add this sub-sirectory after all install steps and other
|
||||
# sub-directories to ensure that all executables are in-place before
|
||||
# any fixup is done
|
||||
add_subdirectory (bundle_fixup)
|
||||
endif ()
|
||||
# install a qt.conf file
|
||||
install (CODE "
|
||||
get_filename_component (the_qt_conf \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" REALPATH)
|
||||
file (WRITE \"\${the_qt_conf}\"
|
||||
\"[Paths]
|
||||
\")
|
||||
"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
# if a system Qt is used (e.g. installed in /usr/lib/), it will not be included in the installation
|
||||
set (fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/${CMAKE_PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
|
||||
#get_filename_component (hamlib_lib_dir ${hamlib_LIBRARIES} PATH)
|
||||
|
||||
if (APPLE)
|
||||
# install required Qt plugins
|
||||
install (
|
||||
DIRECTORY
|
||||
${QT_PLUGINS_DIR}/platforms
|
||||
${QT_PLUGINS_DIR}/audio
|
||||
${QT_PLUGINS_DIR}/accessible
|
||||
${QT_PLUGINS_DIR}/imageformats
|
||||
${QT_PLUGINS_DIR}/styles
|
||||
DESTINATION ${WSJT_PLUGIN_DESTINATION}
|
||||
CONFIGURATIONS Release MinSizeRel RelWithDebInfo
|
||||
#COMPONENT runtime
|
||||
FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*webgl*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*_debug${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}.dSYM" EXCLUDE
|
||||
)
|
||||
install (
|
||||
FILES
|
||||
${QT_PLUGINS_DIR}/sqldrivers/libqsqlite${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
DESTINATION ${WSJT_PLUGIN_DESTINATION}/sqldrivers
|
||||
CONFIGURATIONS Release MinSizeRel RelWithDebInfo
|
||||
#COMPONENT runtime
|
||||
)
|
||||
# install (
|
||||
# DIRECTORY
|
||||
# ${QT_PLUGINS_DIR}/platforms
|
||||
# ${QT_PLUGINS_DIR}/audio
|
||||
# ${QT_PLUGINS_DIR}/accessible
|
||||
# DESTINATION ${WSJT_PLUGIN_DESTINATION}
|
||||
# CONFIGURATIONS Debug
|
||||
# #COMPONENT runtime
|
||||
# FILES_MATCHING PATTERN "*_debug${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
# PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# )
|
||||
|
||||
# add plugins path for Mac Bundle
|
||||
install (CODE "
|
||||
get_filename_component (the_qt_conf \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" REALPATH)
|
||||
file (APPEND \"\${the_qt_conf}\"
|
||||
\"Plugins = PlugIns
|
||||
\")
|
||||
"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
endif (APPLE)
|
||||
|
||||
if (WIN32)
|
||||
# DLL directory
|
||||
#set (hamlib_lib_dir ${hamlib_lib_dir}/../bin)
|
||||
|
||||
get_filename_component (fftw_lib_dir ${FFTW3F_LIBRARY} PATH)
|
||||
list (APPEND fixup_library_dirs ${fftw_lib_dir})
|
||||
|
||||
# install required Qt plugins
|
||||
install (
|
||||
DIRECTORY
|
||||
${QT_PLUGINS_DIR}/platforms
|
||||
${QT_PLUGINS_DIR}/styles
|
||||
${QT_PLUGINS_DIR}/accessible
|
||||
${QT_PLUGINS_DIR}/audio
|
||||
${QT_PLUGINS_DIR}/imageformats
|
||||
DESTINATION ${WSJT_PLUGIN_DESTINATION}
|
||||
CONFIGURATIONS Release MinSizeRel RelWithDebInfo
|
||||
#COMPONENT runtime
|
||||
FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*d${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
)
|
||||
install (
|
||||
FILES
|
||||
${QT_PLUGINS_DIR}/sqldrivers/qsqlite${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
DESTINATION ${WSJT_PLUGIN_DESTINATION}/sqldrivers
|
||||
CONFIGURATIONS Release MinSizeRel RelWithDebInfo
|
||||
#COMPONENT runtime
|
||||
)
|
||||
# install (
|
||||
# DIRECTORY
|
||||
# ${QT_PLUGINS_DIR}/platforms
|
||||
# ${QT_PLUGINS_DIR}/accessible
|
||||
# ${QT_PLUGINS_DIR}/audio
|
||||
# DESTINATION ${WSJT_PLUGIN_DESTINATION}
|
||||
# CONFIGURATIONS Debug
|
||||
# #COMPONENT runtime
|
||||
# FILES_MATCHING PATTERN "*d${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
# PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# )
|
||||
|
||||
# add paths for WIN32
|
||||
file (RELATIVE_PATH _plugins_path "${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}" "${CMAKE_INSTALL_PREFIX}/${WSJT_PLUGIN_DESTINATION}")
|
||||
install (CODE "
|
||||
get_filename_component (the_qt_conf \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" REALPATH)
|
||||
file (APPEND \"\${the_qt_conf}\"
|
||||
\"Plugins = ${_plugins_path}
|
||||
\")
|
||||
"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
set (gp_tool "objdump") # we want MinGW tool - not MSVC (See GetPrerequisites.cmake)
|
||||
endif (WIN32)
|
||||
|
||||
#list (APPEND fixup_library_dirs ${hamlib_lib_dir})
|
||||
list (APPEND fixup_library_dirs ${hamlib_LIBRARY_DIRS})
|
||||
|
||||
install (CODE "
|
||||
get_filename_component (the_path \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_PLUGIN_DESTINATION}\" REALPATH)
|
||||
file (GLOB_RECURSE QTPLUGINS \"\${the_path}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\")
|
||||
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake/Modules ${CMAKE_MODULE_PATH})
|
||||
include (BundleUtilities)
|
||||
set (BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
set (gp_tool ${gp_tool})
|
||||
# canonicalize path in install context
|
||||
get_filename_component (the_exe ${fixup_exe} REALPATH)
|
||||
fixup_bundle (\"\${the_exe}\" \"\${QTPLUGINS}\" \"${fixup_library_dirs}\")"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
endif (APPLE OR WIN32)
|
||||
|
||||
endif (NOT is_debug_build)
|
||||
|
||||
|
||||
#
|
||||
|
@ -18,7 +18,7 @@ class QAudioDeviceInfo;
|
||||
class QDir;
|
||||
class QNetworkAccessManager;
|
||||
class Bands;
|
||||
class FrequencyList_v2_101;
|
||||
class FrequencyList_v2;
|
||||
class StationList;
|
||||
class QStringListModel;
|
||||
class LotWUsers;
|
||||
@ -100,7 +100,6 @@ public:
|
||||
QString my_grid () const;
|
||||
QString Field_Day_Exchange() const;
|
||||
QString RTTY_Exchange() const;
|
||||
QString Contest_Name() const;
|
||||
void setEU_VHF_Contest();
|
||||
QFont text_font () const;
|
||||
QFont decoded_text_font () const;
|
||||
@ -165,8 +164,8 @@ public:
|
||||
Bands * bands ();
|
||||
Bands const * bands () const;
|
||||
IARURegions::Region region () const;
|
||||
FrequencyList_v2_101 * frequencies ();
|
||||
FrequencyList_v2_101 const * frequencies () const;
|
||||
FrequencyList_v2 * frequencies ();
|
||||
FrequencyList_v2 const * frequencies () const;
|
||||
StationList * stations ();
|
||||
StationList const * stations () const;
|
||||
QStringListModel * macros ();
|
||||
@ -182,17 +181,8 @@ public:
|
||||
bool highlight_by_mode () const;
|
||||
bool highlight_only_fields () const;
|
||||
bool include_WAE_entities () const;
|
||||
bool highlight_73 () const;
|
||||
void setSpecial_Q65_Pileup();
|
||||
void setSpecial_Hound();
|
||||
void setSpecial_Fox();
|
||||
void setSpecial_None();
|
||||
bool highlight_DXcall () const;
|
||||
bool highlight_DXgrid () const;
|
||||
bool Individual_Contest_Name() const;
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, WW_DIGI, FOX, HOUND, ARRL_DIGI, Q65_PILEUP};
|
||||
enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, WW_DIGI, FOX, HOUND};
|
||||
SpecialOperatingActivity special_op_id () const;
|
||||
|
||||
struct CalibrationParams
|
||||
@ -225,7 +215,8 @@ public:
|
||||
// This method queries if a CAT and PTT connection is operational.
|
||||
bool is_transceiver_online () const;
|
||||
|
||||
// Start the rig connection, safe and normal to call when rig is already open.
|
||||
// Start the rig connection, safe and normal to call when rig is
|
||||
// already open.
|
||||
bool transceiver_online ();
|
||||
|
||||
// check if a real rig is configured
|
||||
@ -243,8 +234,6 @@ public:
|
||||
// Close down connection to rig.
|
||||
void transceiver_offline ();
|
||||
|
||||
void set_CTY_DAT_version(QString const& version);
|
||||
|
||||
// Set transceiver frequency in Hertz.
|
||||
Q_SLOT void transceiver_frequency (Frequency);
|
||||
|
||||
|
1709
Configuration.ui
@ -1,44 +1,60 @@
|
||||
Notes on WSJT-X Installation for Mac OS X
|
||||
-----------------------------------------
|
||||
|
||||
Important: If you are using the new Mac with the M1 chip then please read
|
||||
the section marked: BEGIN M1. Otherwise BEGIN INTEL applies.
|
||||
|
||||
If you have already downloaded a previous version of WSJT-X then I suggest
|
||||
you change the name in the Applications folder from WSJT-X to WSJT-X_previous
|
||||
before proceeding.
|
||||
|
||||
I recommend that you follow the installation instructions especially if you
|
||||
are moving from v2.5 to v2.6 or later, of WSJT-X or you have upgraded macOS.
|
||||
are moving from v2.2 to v2.3 of WSJT-X or you have upgraded macOS.
|
||||
|
||||
BEGIN M1:
|
||||
|
||||
Double-click on the wsjtx-...-Darwin.dmg file you have downloaded from K1JT's web-site.
|
||||
Make sure that you leave this window open for the remaining installation steps.
|
||||
|
||||
Now open a Terminal window by going to Applications->Utilities and clicking on Terminal.
|
||||
|
||||
Along with this ReadMe file there is a file: com.wsjtx.sysctl.plist which must be copied to a
|
||||
system area by typing these lines in the Terminal window and then pressing the Return key after
|
||||
each line.
|
||||
There are two system variables that must be set manually since the M1 Macs do not recognise
|
||||
automatic parameter settings by means of the sysctl.conf file present in the download.
|
||||
Type these commands - you will be asked for your password which will not be echoed:
|
||||
|
||||
sudo cp /Volumes/WSJT-X/com.wsjtx.sysctl.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/com.wsjtx.sysctl.plist
|
||||
sudo sysctl -w kern.sysv.shmmax=52428800
|
||||
sudo sysctl -w kern.sysv.shmall=25600
|
||||
|
||||
It is important to note that these parameter settings will not survive a reboot. If you
|
||||
need to reboot your Mac, then these commands must be re-entered. Now proceed to NEXT.
|
||||
|
||||
BEGIN INTEL:
|
||||
|
||||
Double-click on the wsjtx-...-Darwin.dmg file you have downloaded from K1JT's web-site.
|
||||
|
||||
Now open a Terminal window by going to Applications->Utilities and clicking on Terminal.
|
||||
|
||||
Along with this ReadMe file there is a file: sysctl.conf which must be copied to a
|
||||
system area by typing this line in the Terminal window and then pressing the Return key.
|
||||
|
||||
sudo cp /Volumes/WSJT-X/sysctl.conf /etc
|
||||
|
||||
you will be asked for your normal password because authorisation is needed to copy this file.
|
||||
(Your password will not be echoed but press the Return key when completed.)
|
||||
|
||||
IMPORTANT: Now re-boot your Mac otherwise these changes will not take effect.
|
||||
|
||||
After the reboot you should re-open the Terminal window as before and you can check
|
||||
that the change has been made by typing:
|
||||
Now re-boot your Mac. This is necessary to install the changes. After the
|
||||
reboot you should re-open the Terminal window as before and you can check that the
|
||||
change has been made by typing:
|
||||
|
||||
sysctl -a | grep sysv.shm
|
||||
|
||||
If shmmax is not shown as 52428800 then contact me since WSJT-X will fail to load with
|
||||
an error message: "Unable to create shared memory segment". If the value of shmmax
|
||||
is shown as 20971520 then it is probable that you have download JTDX. WSJT-X and JTDX
|
||||
cannot both control the shmmax paramter. Contact me for advice.
|
||||
an error message: "Unable to create shared memory segment".
|
||||
|
||||
You can now close the Terminal window. It will not be necessary to repeat this procedure
|
||||
again, even when you download an updated version of WSJT-X. It might be necessary if you
|
||||
upgrade macOS.
|
||||
|
||||
NEXT:
|
||||
|
||||
Drag the WSJT-X app to your preferred location, such as Applications.
|
||||
|
||||
You need to configure your sound card. Visit Applications > Utilities > Audio MIDI
|
||||
@ -65,17 +81,8 @@ and how to access them.
|
||||
Finally, visit the Radio panel. WSJT-X is most effective when operated with CAT
|
||||
control. You will need to install the relevant Mac device driver for your rig,
|
||||
and then re-launch WSJT-X. Return to the Radio panel in Preferences and in
|
||||
the "Serial port" panel select your driver from the list that is presented.
|
||||
|
||||
You may need a device driver for your Mac. The USB/UART Bridge chip inside the Icom,
|
||||
Yaesu and Kenwood radios is a Silicon Labs USB to UART Bridge Controller and the Mac
|
||||
drivers are available here:
|
||||
|
||||
https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers
|
||||
|
||||
Visit the SiLabs site and download v6 for a Mac. Then in WSJT-X if you use the drop-down menu
|
||||
for Serial Port you should see something like /dev/tty.SLAB_USBtoUART if the driver has been
|
||||
installed correctly. Make sure you read the release notes that come with the driver.
|
||||
the "Serial port" panel select your driver from the list that is presented. If you
|
||||
do not know where to get an appropriate driver, contact me.
|
||||
|
||||
WSJT-X needs the Mac clock to be accurate. Visit System Preferences > Date & Time
|
||||
and make sure that Date and Time are set automatically. The drop-down menu will
|
||||
@ -88,23 +95,27 @@ Please email me if you have problems.
|
||||
|
||||
--- John G4KLA (g4kla@rmnjmn.co.uk)
|
||||
|
||||
Addendum: Information about com.wsjtx.sysctl.plist and multiple instances of WSJT-X.
|
||||
Addendum: Information about sysctl.conf and multiple instances of WSJT-X.
|
||||
|
||||
WSJT-X makes use of a block of memory which is shared between different parts of
|
||||
the code. The normal allocation of shared memory on a Mac is insufficient and this
|
||||
has to be increased. The com.wsjtx.sysctl.plist file is used for this purpose. You can
|
||||
use a Mac editor to examine the file. (Do not use another editor - the file
|
||||
has to be increased. The sysctl.conf file is used for this purpose. You can
|
||||
use a Mac editor to examine sysctl.conf. (Do not use another editor - the file
|
||||
would probably be corrupted.)
|
||||
|
||||
It is possible to run two instances of WSJT-X simultaneously. See "Section 16.2
|
||||
Frequently asked Questions" in the User Guide. If you wish to run more than two instances
|
||||
simultaneously, the shmall parameter in the com.wsjtx.sysctl.plist file needs to be modified as follows.
|
||||
simultaneously, the shmall parameter in the sysctl.conf file needs to be modified as follows.
|
||||
|
||||
The shmall parameter determines the amount of shared memory which is allocated in 4096 byte pages
|
||||
with 50MB (52428800) required for each instance. The shmall parameter is calculated as:
|
||||
(n * 52428800)/4096 where 'n' is the number of instances required to run simultaneously.
|
||||
Replace your new version of this file in /Library/LaunchDaemons and remember to reboot your
|
||||
Mac afterwards.
|
||||
(n * 52428800)/4096 where 'n' is the number of instances required to run simultaneously. If
|
||||
you are using an Intel Mac, modify the shmall parameter in the sysctl.conf file using a Mac editor
|
||||
and then install in the /etc directory using the installation procedure described above for an
|
||||
Intel Mac. Remember to reboot your Mac afterwards.
|
||||
|
||||
If you are using an M1 Mac, then simply issue the sudo sysctl -w kern.sysv.shmall=xxx command where
|
||||
xxx is the new value of shmall that is required.
|
||||
|
||||
Note that the shmmax parameter remains unchanged. This is the maximum amount of shared memory that
|
||||
any one instance is allowed to request from the total shared memory allocation and should not
|
||||
@ -114,9 +125,3 @@ If two instances of WSJT-X are running, it is likely that you might need additio
|
||||
audio devices, from two rigs for example. Visit Audio MIDI Setup and create an Aggregate Device
|
||||
which will allow you to specify more than one interface. I recommend you consult Apple's guide
|
||||
on combining multiple audio interfaces which is at https://support.apple.com/en-us/HT202000.
|
||||
|
||||
2. Preventing WSJT-X from being put into 'sleep' mode (App Nap).
|
||||
|
||||
In normal circumstances an application which has not been directly accessed for a while can be
|
||||
subject to App Nap which means it is suspended until such time as its windows are accessed. If
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.wsjtx.sysctl</string>
|
||||
<key>Program</key>
|
||||
<string>/usr/sbin/sysctl</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/sbin/sysctl</string>
|
||||
<string>kern.sysv.shmmax=52428800</string>
|
||||
<string>kern.sysv.shmall=25600</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
5
Darwin/sysctl.conf
Normal file
@ -0,0 +1,5 @@
|
||||
kern.sysv.shmmax=52428800
|
||||
kern.sysv.shmmin=1
|
||||
kern.sysv.shmmni=128
|
||||
kern.sysv.shmseg=32
|
||||
kern.sysv.shmall=25600
|
@ -11,39 +11,7 @@ extern "C" {
|
||||
|
||||
namespace
|
||||
{
|
||||
QRegularExpression tokens_re {R"(
|
||||
^
|
||||
(?:(?<dual>[A-Z0-9/]+)\sRR73;\s)? # dual reply DXpedition message
|
||||
(?:
|
||||
(?<word1>
|
||||
(?:CQ|DE|QRZ)
|
||||
(?:\s?DX|\s
|
||||
(?:[A-Z]{1,4}|\d{3}) # directional CQ
|
||||
)
|
||||
| [A-Z0-9/]+ # DX call
|
||||
|\.{3} # unknown hash code
|
||||
)\s
|
||||
)
|
||||
(?:
|
||||
(?<word2>[A-Z0-9/]+) # DE call
|
||||
(?:\s
|
||||
(?<word3>[-+A-Z0-9]+) # report
|
||||
(?:\s
|
||||
(?<word4>
|
||||
(?:
|
||||
OOO # EME
|
||||
| (?!RR73)[A-R]{2}[0-9]{2} # grid square (not RR73)
|
||||
| 5[0-9]{5} # EU VHF Contest report & serial
|
||||
)
|
||||
)
|
||||
(?:\s
|
||||
(?<word5>[A-R]{2}[0-9]{2}[A-X]{2}) # EU VHF Contest grid locator
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)"
|
||||
, QRegularExpression::ExtendedPatternSyntaxOption};
|
||||
QRegularExpression words_re {R"(^(?:(?<word1>(?:CQ|DE|QRZ)(?:\s?DX|\s(?:[A-Z]{1,4}|\d{3}))|[A-Z0-9/]+|\.{3})\s)(?:(?<word2>[A-Z0-9/]+)(?:\s(?<word3>[-+A-Z0-9]+)(?:\s(?<word4>(?:OOO|(?!RR73)[A-R]{2}[0-9]{2})))?)?)?)"};
|
||||
}
|
||||
|
||||
DecodedText::DecodedText (QString const& the_string)
|
||||
@ -55,15 +23,13 @@ DecodedText::DecodedText (QString const& the_string)
|
||||
, is_standard_ {false}
|
||||
{
|
||||
// discard appended AP info
|
||||
clean_string_.replace (QRegularExpression {R"(^(.*?)(?:\?\s)?[aq][0-9].*$)"}, "\\1");
|
||||
clean_string_.replace (QRegularExpression {R"(^(.*)(?:(?:\?\s)?a[0-9].*)$)"}, "\\1");
|
||||
|
||||
// qDebug () << "DecodedText: the_string:" << the_string << "Nbsp pos:" << the_string.indexOf (QChar::Nbsp);
|
||||
if (message_.length() >= 1)
|
||||
{
|
||||
// remove appended confidence (?) and ap designators before truncating the message
|
||||
message_ = clean_string_.mid (column_qsoText + padding_).trimmed ();
|
||||
message0_ = message_.left(37);
|
||||
message_ = message_.left(37).remove (QRegularExpression {"[<>]"});
|
||||
message0_ = message_.left(36);
|
||||
message_ = message_.left(36).remove (QRegularExpression {"[<>]"});
|
||||
int i1 = message_.indexOf ('\r');
|
||||
if (i1 > 0)
|
||||
{
|
||||
@ -94,13 +60,11 @@ QStringList DecodedText::messageWords () const
|
||||
// extract up to the first four message words
|
||||
QString t=message_;
|
||||
if(t.left(4)=="TU; ") t=message_.mid(4,-1);
|
||||
return tokens_re.match(t).capturedTexts();
|
||||
return words_re.match(t).capturedTexts();
|
||||
}
|
||||
// simple word split for free text messages
|
||||
auto words = message_.split (' ', SkipEmptyParts);
|
||||
// add whole message and two empty strings as item 0 & 1 to mimic RE
|
||||
// capture list
|
||||
words.prepend (QString {});
|
||||
// add whole message as item 0 to mimic RE capture list
|
||||
words.prepend (message_);
|
||||
return words;
|
||||
}
|
||||
@ -130,7 +94,7 @@ bool DecodedText::isTX() const
|
||||
|
||||
bool DecodedText::isLowConfidence () const
|
||||
{
|
||||
return QChar {'?'} == string_.mid (padding_ + column_qsoText + 36, 1);
|
||||
return QChar {'?'} == string_.mid (padding_ + column_qsoText + 21, 1);
|
||||
}
|
||||
|
||||
int DecodedText::frequencyOffset() const
|
||||
@ -164,23 +128,18 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /
|
||||
if (message_.size () < 1) return false;
|
||||
|
||||
QStringList const& w = message_.split(" ", SkipEmptyParts);
|
||||
int offset {0};
|
||||
if (w.size () > 2)
|
||||
{
|
||||
if ("RR73;" == w[1] && w.size () > 3)
|
||||
{
|
||||
offset = 2;
|
||||
}
|
||||
if (is_standard_ && (w[offset] == myBaseCall
|
||||
|| w[offset].endsWith ("/" + myBaseCall)
|
||||
|| w[offset].startsWith (myBaseCall + "/")
|
||||
|| (w.size () > offset + 1 && !dxBaseCall.isEmpty ()
|
||||
&& (w[offset + 1] == dxBaseCall
|
||||
|| w[offset + 1].endsWith ("/" + dxBaseCall)
|
||||
|| w[offset + 1].startsWith (dxBaseCall + "/")))))
|
||||
if (w.size ()
|
||||
&& is_standard_ && (w[0] == myBaseCall
|
||||
|| w[0].endsWith ("/" + myBaseCall)
|
||||
|| w[0].startsWith (myBaseCall + "/")
|
||||
|| (w.size () > 1 && !dxBaseCall.isEmpty ()
|
||||
&& (w[1] == dxBaseCall
|
||||
|| w[1].endsWith ("/" + dxBaseCall)
|
||||
|| w[1].startsWith (dxBaseCall + "/")))))
|
||||
{
|
||||
QString tt="";
|
||||
if(w.size() > 2) tt=w[2];
|
||||
bool ok;
|
||||
auto tt = w[offset + 2];
|
||||
auto i1=tt.toInt(&ok);
|
||||
if (ok and i1>=-50 and i1<50)
|
||||
{
|
||||
@ -198,14 +157,13 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return is_standard_;
|
||||
}
|
||||
|
||||
// get the first text word, usually the call
|
||||
QString DecodedText::call() const
|
||||
{
|
||||
return tokens_re.match (message_).captured ("word1");
|
||||
return words_re.match (message_).captured ("word1");
|
||||
}
|
||||
|
||||
// get the second word, most likely the de call and the third word, most likely grid
|
||||
@ -217,7 +175,7 @@ void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid) const
|
||||
{
|
||||
msg = msg.mid (p + 2);
|
||||
}
|
||||
auto const& match = tokens_re.match (msg);
|
||||
auto const& match = words_re.match (msg);
|
||||
call = match.captured ("word2");
|
||||
grid = match.captured ("word3");
|
||||
if ("R" == grid) grid = match.captured ("word4");
|
||||
|
@ -443,7 +443,7 @@ void EqualizationToolsDialog::impl::plot_current ()
|
||||
plot_.graph (3)->rescaleValueAxis ();
|
||||
|
||||
QFileInfo refspec_file_info {data_directory_.absoluteFilePath ("refspec.dat")};
|
||||
std::ifstream refspec_file (refspec_file_info.absoluteFilePath ().toLocal8Bit ().constData (), std::ifstream::in);
|
||||
std::ifstream refspec_file (refspec_file_info.absoluteFilePath ().toLatin1 ().constData (), std::ifstream::in);
|
||||
unsigned n;
|
||||
if (refspec_file >> amp_poly_low_ >> amp_poly_high_ >> n)
|
||||
{
|
||||
@ -499,7 +499,7 @@ void EqualizationToolsDialog::impl::plot_phase ()
|
||||
, "Phase Coefficient Files (*.pcoeff)");
|
||||
if (!phase_file_name.size ()) return;
|
||||
|
||||
std::ifstream phase_file (phase_file_name.toLocal8Bit ().constData (), std::ifstream::in);
|
||||
std::ifstream phase_file (phase_file_name.toLatin1 ().constData (), std::ifstream::in);
|
||||
int n;
|
||||
float chi;
|
||||
float rmsdiff;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include <boost/log/core.hpp>
|
||||
#include "Logger.hpp"
|
||||
|
||||
class QObject;
|
||||
@ -13,8 +12,8 @@ class QEvent;
|
||||
// We can't use the GUI after QApplication::exit() is called so
|
||||
// uncaught exceptions can get lost on Windows systems where there is
|
||||
// no console terminal, so here we override QApplication::notify() and
|
||||
// wrap the base class call with a try block to catch and log any
|
||||
// uncaught exceptions.
|
||||
// wrap the base class call with a try block to catch and display
|
||||
// exceptions in a message box.
|
||||
//
|
||||
class ExceptionCatchingApplication
|
||||
: public QApplication
|
||||
@ -32,16 +31,12 @@ public:
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
LOG_FATAL ("Unexpected exception caught in event loop: " << e.what ());
|
||||
LOG_FATAL (e.what ());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_FATAL ("Unexpected unknown exception caught in event loop");
|
||||
LOG_FATAL ("Unexpected fatal error");
|
||||
}
|
||||
// There's nowhere to go from here as Qt will not pass exceptions
|
||||
// through the event loop, so we must abort.
|
||||
boost::log::core::get ()->flush ();
|
||||
qFatal ("Aborting");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
36
INSTALL
@ -16,7 +16,8 @@ Installing WSJT-X
|
||||
|
||||
Binary packages of WSJT-X are available from the project web site:
|
||||
|
||||
https://wsjt.sourceforge.io/wsjtx.html
|
||||
http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html
|
||||
|
||||
|
||||
Building from Source
|
||||
====================
|
||||
@ -27,7 +28,7 @@ the Boost C++ libraries. For MS Windows see the section "Building
|
||||
from Source on MS Windows" below. For Apple Mac see the section
|
||||
"Building from Source on Apple Mac".
|
||||
|
||||
Qt v5, preferably v5.12 or later is required to build WSJT-X.
|
||||
Qt v5, preferably v5.9 or later is required to build WSJT-X.
|
||||
|
||||
Qt v5 multimedia support, serial port, and Linguist is necessary as
|
||||
well as the core Qt v5 components, normally installing the Qt
|
||||
@ -50,13 +51,15 @@ normally you can choose not to install libusb-1.0-dev but if you have
|
||||
a SoftRock USB or similar SDR that uses a custom USB interface then it
|
||||
is required.
|
||||
|
||||
The Hamlib library is required. WSJT-X can be built with any version
|
||||
of the Hamlib git master. To build Hamlib from sources something
|
||||
like the following recipe should suffice:
|
||||
The Hamlib library is required. Currently WSJT-X needs to be built
|
||||
using a forked version of the Hamlib git master. This fork contains
|
||||
patches not yet accepted by the Hamlib development team which are
|
||||
essential for correct operation of WSJT-X. To build the Hamlib fork
|
||||
from sources something like the following recipe should suffice:
|
||||
|
||||
$ mkdir ~/hamlib-prefix
|
||||
$ cd ~/hamlib-prefix
|
||||
$ git clone https://github.com/Hamlib/Hamlib src
|
||||
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
|
||||
$ cd src
|
||||
$ git checkout integration
|
||||
$ ./bootstrap
|
||||
@ -111,13 +114,13 @@ Building from Source on MS Windows
|
||||
|
||||
Because building on MS Windows is quite complicated there is an
|
||||
Software Development Kit available that provides all the prerequisite
|
||||
libraries and tools for building WSJT-X. This SDK is called HAMLIB SDK
|
||||
libraries and tools for building WSJT-X. This SDK is called JT-SDK-QT
|
||||
which is documented here:
|
||||
|
||||
https://sourceforge.net/projects/hamlib-sdk/
|
||||
http://physics.princeton.edu/pulsar/K1JT/wsjtx-doc/dev-guide-main.html
|
||||
|
||||
If you need to build Hamlib rather than use the Hamlib kit included in
|
||||
the HAMLIB SDK the following recipe should help. Reasons for building
|
||||
the JT-SDK the following recipe should help. Reasons for building
|
||||
Hamlib from source might include picking up the very latest patches or
|
||||
building a different branch that you wish to contribute to.
|
||||
|
||||
@ -141,7 +144,7 @@ In an MSYS shell:-
|
||||
|
||||
$ mkdir ~/hamib-prefix
|
||||
$ cd ~/hamlib-prefix
|
||||
$ git clone https://github.com/Hamlib/Hamlib src
|
||||
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
|
||||
$ cd src
|
||||
$ git checkout integration
|
||||
$ ./bootstrap
|
||||
@ -176,6 +179,10 @@ Hamlib binary location as one of the paths in CMAKE_PREFIX_PATH.
|
||||
Building from Source on Apple Mac
|
||||
=================================
|
||||
|
||||
These instructions are adapted from my Evernote page at:
|
||||
|
||||
https://www.evernote.com/pub/bsomervi/wsjt-xmacbuilds
|
||||
|
||||
There are several ways to get the required GNU and other open source
|
||||
tools and libraries installed, my preference is MacPorts because it is
|
||||
easy to use and does everything we need.
|
||||
@ -222,11 +229,12 @@ instructions are here:
|
||||
|
||||
Hamlib
|
||||
------
|
||||
First fetch hamlib from the git master repository:
|
||||
First fetch hamlib from the repository, in this case my fork of Hamlib
|
||||
3 until the official repository has all the fixes we need:
|
||||
|
||||
$ mkdir -p ~/hamlib-prefix/build
|
||||
$ cd ~/hamlib-prefix
|
||||
$ git clone https://github.com/Hamlib/Hamlib src
|
||||
$ git clone git://git.code.sf.net/u/bsomervi/hamlib src
|
||||
$ cd src
|
||||
$ git checkout integration
|
||||
$ ./bootstrap
|
||||
@ -345,8 +353,8 @@ which installs the WSJT-X application bundle into ~/wsjtx-prefix
|
||||
Updating and Rebuilding Hamlib
|
||||
==============================
|
||||
|
||||
From time to time new fixes will be pushed to the Hamlib git
|
||||
master repository. To pick them up type:
|
||||
From time to time new fixes will be pushed to the Hamlib fork
|
||||
repository integration branch. To pick them up type:
|
||||
|
||||
$ cd ~/hamlib-prefix/src
|
||||
$ git pull
|
||||
|
@ -142,8 +142,8 @@ namespace Logger
|
||||
err += e.what ();
|
||||
// Since we cannot be sure of boost log state, output to cerr and cout.
|
||||
std::cerr << "ERROR: " << err << std::endl;
|
||||
std::cout << "ERROR: " << err << std::endl;
|
||||
LOG_ERROR (err);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,13 +52,9 @@ void register_types ()
|
||||
|
||||
item_editor_factory->registerEditor (qMetaTypeId<QDateTime> (), new QStandardItemEditorCreator<DateTimeEdit> ());
|
||||
|
||||
// V101 Frequency list model
|
||||
qRegisterMetaTypeStreamOperators<FrequencyList_v2_101::Item> ("Item_v2_101");
|
||||
QMetaType::registerConverter<FrequencyList_v2_101::Item, QString> (&FrequencyList_v2_101::Item::toString);
|
||||
qRegisterMetaTypeStreamOperators<FrequencyList_v2_101::FrequencyItems> ("FrequencyItems_v2_101");
|
||||
|
||||
// V100 Frequency list model
|
||||
// Frequency list model
|
||||
qRegisterMetaTypeStreamOperators<FrequencyList_v2::Item> ("Item_v2");
|
||||
QMetaType::registerConverter<FrequencyList_v2::Item, QString> (&FrequencyList_v2::Item::toString);
|
||||
qRegisterMetaTypeStreamOperators<FrequencyList_v2::FrequencyItems> ("FrequencyItems_v2");
|
||||
|
||||
// defunct old versions
|
||||
|
@ -66,7 +66,7 @@ private:
|
||||
double m_dphi;
|
||||
double m_amp;
|
||||
double m_nsps;
|
||||
double m_frequency;
|
||||
double volatile m_frequency;
|
||||
double m_frequency0;
|
||||
double m_snr;
|
||||
double m_fac;
|
||||
@ -80,9 +80,9 @@ private:
|
||||
qint16 m_ramp;
|
||||
|
||||
unsigned m_frameRate;
|
||||
ModulatorState m_state;
|
||||
ModulatorState volatile m_state;
|
||||
|
||||
bool m_tuning;
|
||||
bool volatile m_tuning;
|
||||
bool m_addNoise;
|
||||
bool m_bFastMode;
|
||||
|
||||
|
@ -1,229 +0,0 @@
|
||||
|
||||
#include "FileDownload.hpp"
|
||||
#include <QCoreApplication>
|
||||
#include <QUrl>
|
||||
#include <QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QIODevice>
|
||||
#include "qt_helpers.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
FileDownload::FileDownload() : QObject(nullptr)
|
||||
{
|
||||
redirect_count_ = 0;
|
||||
url_valid_ = false;
|
||||
}
|
||||
|
||||
FileDownload::~FileDownload()
|
||||
{
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
void FileDownload::errorOccurred(QNetworkReply::NetworkError code)
|
||||
{
|
||||
LOG_INFO(QString{"FileDownload [%1]: errorOccurred %2 -> %3"}.arg(user_agent_).arg(code).arg(reply_->errorString()));
|
||||
Q_EMIT error (reply_->errorString ());
|
||||
destfile_.cancelWriting ();
|
||||
destfile_.commit ();
|
||||
}
|
||||
#else
|
||||
void FileDownload::obsoleteError()
|
||||
{
|
||||
LOG_INFO(QString{"FileDownload [%1]: error -> %3"}.arg(user_agent_).arg(reply_->errorString()));
|
||||
Q_EMIT error (reply_->errorString ());
|
||||
destfile_.cancelWriting ();
|
||||
destfile_.commit ();
|
||||
}
|
||||
#endif
|
||||
|
||||
void FileDownload::configure(QNetworkAccessManager *network_manager, const QString &source_url, const QString &destination_path, const QString &user_agent)
|
||||
{
|
||||
manager_ = network_manager;
|
||||
source_url_ = source_url;
|
||||
destination_filename_ = destination_path;
|
||||
user_agent_ = user_agent;
|
||||
}
|
||||
|
||||
void FileDownload::store()
|
||||
{
|
||||
if (destfile_.isOpen())
|
||||
destfile_.write (reply_->read (reply_->bytesAvailable ()));
|
||||
else
|
||||
LOG_INFO(QString{ "FileDownload [%1]: file is not open."}.arg(user_agent_));
|
||||
}
|
||||
|
||||
void FileDownload::replyComplete()
|
||||
{
|
||||
QFileInfo destination_file(destination_filename_);
|
||||
QDir tmpdir_(destination_file.absoluteFilePath());
|
||||
|
||||
LOG_DEBUG(QString{ "FileDownload [%1]: replyComplete"}.arg(user_agent_));
|
||||
if (!reply_)
|
||||
{
|
||||
Q_EMIT load_finished ();
|
||||
return; // we probably deleted it in an earlier call
|
||||
}
|
||||
|
||||
QUrl redirect_url {reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ()};
|
||||
|
||||
if (reply_->error () == QNetworkReply::NoError && !redirect_url.isEmpty ())
|
||||
{
|
||||
if ("https" == redirect_url.scheme () && !QSslSocket::supportsSsl ())
|
||||
{
|
||||
Q_EMIT download_error (tr ("Network Error - SSL/TLS support not installed, cannot fetch:\n\'%1\'")
|
||||
.arg (redirect_url.toDisplayString ()));
|
||||
url_valid_ = false; // reset
|
||||
Q_EMIT load_finished ();
|
||||
}
|
||||
else if (++redirect_count_ < 10) // maintain sanity
|
||||
{
|
||||
// follow redirect
|
||||
download (reply_->url ().resolved (redirect_url));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_EMIT download_error (tr ("Network Error - Too many redirects:\n\'%1\'")
|
||||
.arg (redirect_url.toDisplayString ()));
|
||||
url_valid_ = false; // reset
|
||||
Q_EMIT load_finished ();
|
||||
}
|
||||
}
|
||||
else if (reply_->error () != QNetworkReply::NoError)
|
||||
{
|
||||
destfile_.cancelWriting();
|
||||
destfile_.commit();
|
||||
url_valid_ = false; // reset
|
||||
// report errors that are not due to abort
|
||||
if (QNetworkReply::OperationCanceledError != reply_->error ())
|
||||
{
|
||||
Q_EMIT download_error (tr ("Network Error:\n%1")
|
||||
.arg (reply_->errorString ()));
|
||||
}
|
||||
Q_EMIT load_finished ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!url_valid_)
|
||||
{
|
||||
// now get the body content
|
||||
url_valid_ = true;
|
||||
download (reply_->url ().resolved (redirect_url));
|
||||
}
|
||||
else // the body has completed. Save it.
|
||||
{
|
||||
url_valid_ = false; // reset
|
||||
// load the database asynchronously
|
||||
// future_load_ = std::async (std::launch::async, &LotWUsers::impl::load_dictionary, this, csv_file_.fileName ());
|
||||
LOG_INFO(QString{ "FileDownload [%1]: complete. File path is %2"}.arg(user_agent_).arg(destfile_.fileName()));
|
||||
destfile_.commit();
|
||||
emit complete(destination_filename_);
|
||||
}
|
||||
}
|
||||
|
||||
if (reply_ && reply_->isFinished ())
|
||||
{
|
||||
reply_->deleteLater ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FileDownload::downloadComplete(QNetworkReply *data)
|
||||
{
|
||||
// make a temp file in the same place as the file we're downloading. Needs to be on the same
|
||||
// filesystem as where we eventually want to 'mv' it.
|
||||
|
||||
QUrl r = request_.url();
|
||||
LOG_INFO(QString{"FileDownload [%1]: finished %2 of %3 -> %4 (%5)"}.arg(user_agent_).arg(data->operation()).arg(source_url_).arg(destination_filename_).arg(r.url()));
|
||||
|
||||
#ifdef DEBUG_FILEDOWNLOAD
|
||||
LOG_INFO("Request Headers:");
|
||||
Q_FOREACH (const QByteArray& hdr, request_.rawHeaderList()) {
|
||||
LOG_INFO(QString{ "%1 -> %2"}.arg(QString(hdr)).arg(QString(request_.rawHeader(hdr))));
|
||||
}
|
||||
|
||||
LOG_INFO("Response Headers:");
|
||||
Q_FOREACH (const QByteArray& hdr, reply_->rawHeaderList()) {
|
||||
LOG_INFO(QString{ "%1 -> %2"}.arg(QString(hdr)).arg(QString(reply_->rawHeader(hdr))));
|
||||
}
|
||||
#endif
|
||||
data->deleteLater();
|
||||
}
|
||||
|
||||
void FileDownload::start_download()
|
||||
{
|
||||
url_valid_ = false;
|
||||
download(QUrl(source_url_));
|
||||
}
|
||||
|
||||
void FileDownload::download(QUrl qurl)
|
||||
{
|
||||
request_.setUrl(qurl);
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
if (QNetworkAccessManager::Accessible != manager_->networkAccessible ())
|
||||
{
|
||||
// try and recover network access for QNAM
|
||||
manager_->setNetworkAccessible (QNetworkAccessManager::Accessible);
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_INFO(QString{"FileDownload [%1]: Starting download of %2 to %3"}.arg(user_agent_).arg(source_url_).arg(destination_filename_));
|
||||
|
||||
request_.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
request_.setRawHeader("Accept", "*/*");
|
||||
request_.setRawHeader ("User-Agent", user_agent_.toLocal8Bit()); // Must have a UA for some sites, like country-files
|
||||
|
||||
if (!url_valid_)
|
||||
{
|
||||
reply_ = manager_->head(request_);
|
||||
}
|
||||
else
|
||||
{
|
||||
reply_ = manager_->get (request_);
|
||||
}
|
||||
|
||||
QObject::connect(manager_, &QNetworkAccessManager::finished, this, &FileDownload::downloadComplete, Qt::UniqueConnection);
|
||||
QObject::connect(reply_, &QNetworkReply::downloadProgress, this, &FileDownload::downloadProgress, Qt::UniqueConnection);
|
||||
QObject::connect(reply_, &QNetworkReply::finished, this, &FileDownload::replyComplete, Qt::UniqueConnection);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
QObject::connect(reply_, &QNetworkReply::errorOccurred,this, &FileDownload::errorOccurred, Qt::UniqueConnection);
|
||||
#else
|
||||
QObject::connect(reply_, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &FileDownload::obsoleteError, Qt::UniqueConnection);
|
||||
#endif
|
||||
QObject::connect(reply_, &QNetworkReply::readyRead, this, &FileDownload::store, Qt::UniqueConnection);
|
||||
|
||||
QFileInfo destination_file(destination_filename_);
|
||||
QString const tmpfile_base = destination_file.fileName();
|
||||
QString const &tmpfile_path = destination_file.absolutePath();
|
||||
QDir tmpdir{};
|
||||
if (!tmpdir.mkpath(tmpfile_path))
|
||||
{
|
||||
LOG_INFO(QString{"FileDownload [%1]: Directory %2 does not exist"}.arg(user_agent_).arg(tmpfile_path).arg(
|
||||
destfile_.errorString()));
|
||||
}
|
||||
|
||||
if (url_valid_) {
|
||||
destfile_.setFileName(destination_file.absoluteFilePath());
|
||||
if (!destfile_.open(QSaveFile::WriteOnly | QIODevice::WriteOnly)) {
|
||||
LOG_INFO(QString{"FileDownload [%1]: Unable to open %2: %3"}.arg(user_agent_).arg(destfile_.fileName()).arg(
|
||||
destfile_.errorString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileDownload::downloadProgress(qint64 received, qint64 total)
|
||||
{
|
||||
LOG_DEBUG(QString{"FileDownload: [%1] Progress %2 from %3, total %4, so far %5"}.arg(user_agent_).arg(destination_filename_).arg(source_url_).arg(total).arg(received));
|
||||
Q_EMIT progress(QString{"%4 bytes downloaded"}.arg(received));
|
||||
}
|
||||
|
||||
void FileDownload::abort ()
|
||||
{
|
||||
if (reply_ && reply_->isRunning ())
|
||||
{
|
||||
reply_->abort ();
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
#ifndef WSJTX_FILEDOWNLOAD_H
|
||||
#define WSJTX_FILEDOWNLOAD_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QPointer>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QTemporaryFile>
|
||||
#include <QSaveFile>
|
||||
|
||||
class FileDownload : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FileDownload();
|
||||
~FileDownload();
|
||||
|
||||
void configure(QNetworkAccessManager *network_manager, const QString& source_url, const QString& destination_filename, const QString& user_agent);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *manager_;
|
||||
QString source_url_;
|
||||
QString destination_filename_;
|
||||
QString user_agent_;
|
||||
QPointer<QNetworkReply> reply_;
|
||||
QNetworkRequest request_;
|
||||
QSaveFile destfile_;
|
||||
bool url_valid_;
|
||||
int redirect_count_;
|
||||
signals:
|
||||
void complete(QString filename);
|
||||
void progress(QString filename);
|
||||
void load_finished() const;
|
||||
void download_error (QString const& reason) const;
|
||||
void error(QString const& reason) const;
|
||||
|
||||
|
||||
public slots:
|
||||
void start_download();
|
||||
void download(QUrl url);
|
||||
void store();
|
||||
void abort();
|
||||
void downloadComplete(QNetworkReply* data);
|
||||
void downloadProgress(qint64 recieved, qint64 total);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
void errorOccurred(QNetworkReply::NetworkError code);
|
||||
#else
|
||||
void obsoleteError();
|
||||
#endif
|
||||
void replyComplete();
|
||||
};
|
||||
|
||||
#endif //WSJTX_FILEDOWNLOAD_H
|
@ -16,9 +16,7 @@
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QDebug>
|
||||
#include "qt_helpers.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "FileDownload.hpp"
|
||||
|
||||
#include "pimpl_impl.hpp"
|
||||
|
||||
#include "moc_LotWUsers.cpp"
|
||||
@ -41,7 +39,6 @@ public:
|
||||
, url_valid_ {false}
|
||||
, redirect_count_ {0}
|
||||
, age_constraint_ {365}
|
||||
, connected_ {false}
|
||||
{
|
||||
}
|
||||
|
||||
@ -52,35 +49,13 @@ public:
|
||||
auto exists = QFileInfo::exists (csv_file_name);
|
||||
if (fetch && (!exists || forced_fetch))
|
||||
{
|
||||
current_url_.setUrl(url);
|
||||
if (current_url_.isValid() && !QSslSocket::supportsSsl())
|
||||
current_url_.setUrl (url);
|
||||
if (current_url_.isValid () && !QSslSocket::supportsSsl ())
|
||||
{
|
||||
current_url_.setScheme("http");
|
||||
current_url_.setScheme ("http");
|
||||
}
|
||||
redirect_count_ = 0;
|
||||
|
||||
Q_EMIT self_->progress (QString("Starting download from %1").arg(url));
|
||||
|
||||
lotw_downloader_.configure(network_manager_,
|
||||
url,
|
||||
csv_file_name,
|
||||
"WSJT-X LotW User Downloader");
|
||||
if (!connected_)
|
||||
{
|
||||
connect(&lotw_downloader_, &FileDownload::complete, [this, csv_file_name] {
|
||||
LOG_INFO(QString{"LotWUsers: Loading LotW file %1"}.arg(csv_file_name));
|
||||
future_load_ = std::async(std::launch::async, &LotWUsers::impl::load_dictionary, this, csv_file_name);
|
||||
});
|
||||
connect(&lotw_downloader_, &FileDownload::error, [this] (QString const& msg) {
|
||||
LOG_INFO(QString{"LotWUsers: Error downloading LotW file: %1"}.arg(msg));
|
||||
Q_EMIT self_->LotW_users_error (msg);
|
||||
});
|
||||
connect( &lotw_downloader_, &FileDownload::progress, [this] (QString const& msg) {
|
||||
Q_EMIT self_->progress (msg);
|
||||
});
|
||||
connected_ = true;
|
||||
}
|
||||
lotw_downloader_.start_download();
|
||||
download (current_url_);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -92,9 +67,142 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void download (QUrl url)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
if (QNetworkAccessManager::Accessible != network_manager_->networkAccessible ())
|
||||
{
|
||||
// try and recover network access for QNAM
|
||||
network_manager_->setNetworkAccessible (QNetworkAccessManager::Accessible);
|
||||
}
|
||||
#endif
|
||||
|
||||
QNetworkRequest request {url};
|
||||
request.setRawHeader ("User-Agent", "WSJT LotW User Downloader");
|
||||
request.setOriginatingObject (this);
|
||||
|
||||
// this blocks for a second or two the first time it is used on
|
||||
// Windows - annoying
|
||||
if (!url_valid_)
|
||||
{
|
||||
reply_ = network_manager_->head (request);
|
||||
}
|
||||
else
|
||||
{
|
||||
reply_ = network_manager_->get (request);
|
||||
}
|
||||
|
||||
connect (reply_.data (), &QNetworkReply::finished, this, &LotWUsers::impl::reply_finished);
|
||||
connect (reply_.data (), &QNetworkReply::readyRead, this, &LotWUsers::impl::store);
|
||||
}
|
||||
|
||||
void reply_finished ()
|
||||
{
|
||||
if (!reply_)
|
||||
{
|
||||
Q_EMIT self_->load_finished ();
|
||||
return; // we probably deleted it in an earlier call
|
||||
}
|
||||
QUrl redirect_url {reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ()};
|
||||
if (reply_->error () == QNetworkReply::NoError && !redirect_url.isEmpty ())
|
||||
{
|
||||
if ("https" == redirect_url.scheme () && !QSslSocket::supportsSsl ())
|
||||
{
|
||||
Q_EMIT self_->LotW_users_error (tr ("Network Error - SSL/TLS support not installed, cannot fetch:\n\'%1\'")
|
||||
.arg (redirect_url.toDisplayString ()));
|
||||
url_valid_ = false; // reset
|
||||
Q_EMIT self_->load_finished ();
|
||||
}
|
||||
else if (++redirect_count_ < 10) // maintain sanity
|
||||
{
|
||||
// follow redirect
|
||||
download (reply_->url ().resolved (redirect_url));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_EMIT self_->LotW_users_error (tr ("Network Error - Too many redirects:\n\'%1\'")
|
||||
.arg (redirect_url.toDisplayString ()));
|
||||
url_valid_ = false; // reset
|
||||
Q_EMIT self_->load_finished ();
|
||||
}
|
||||
}
|
||||
else if (reply_->error () != QNetworkReply::NoError)
|
||||
{
|
||||
csv_file_.cancelWriting ();
|
||||
csv_file_.commit ();
|
||||
url_valid_ = false; // reset
|
||||
// report errors that are not due to abort
|
||||
if (QNetworkReply::OperationCanceledError != reply_->error ())
|
||||
{
|
||||
Q_EMIT self_->LotW_users_error (tr ("Network Error:\n%1")
|
||||
.arg (reply_->errorString ()));
|
||||
}
|
||||
Q_EMIT self_->load_finished ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (url_valid_ && !csv_file_.commit ())
|
||||
{
|
||||
Q_EMIT self_->LotW_users_error (tr ("File System Error - Cannot commit changes to:\n\"%1\"")
|
||||
.arg (csv_file_.fileName ()));
|
||||
url_valid_ = false; // reset
|
||||
Q_EMIT self_->load_finished ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!url_valid_)
|
||||
{
|
||||
// now get the body content
|
||||
url_valid_ = true;
|
||||
download (reply_->url ().resolved (redirect_url));
|
||||
}
|
||||
else
|
||||
{
|
||||
url_valid_ = false; // reset
|
||||
// load the database asynchronously
|
||||
future_load_ = std::async (std::launch::async, &LotWUsers::impl::load_dictionary, this, csv_file_.fileName ());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reply_ && reply_->isFinished ())
|
||||
{
|
||||
reply_->deleteLater ();
|
||||
}
|
||||
}
|
||||
|
||||
void store ()
|
||||
{
|
||||
if (url_valid_)
|
||||
{
|
||||
if (!csv_file_.isOpen ())
|
||||
{
|
||||
// create temporary file in the final location
|
||||
if (!csv_file_.open (QSaveFile::WriteOnly))
|
||||
{
|
||||
abort ();
|
||||
Q_EMIT self_->LotW_users_error (tr ("File System Error - Cannot open file:\n\"%1\"\nError(%2): %3")
|
||||
.arg (csv_file_.fileName ())
|
||||
.arg (csv_file_.error ())
|
||||
.arg (csv_file_.errorString ()));
|
||||
}
|
||||
}
|
||||
if (csv_file_.write (reply_->read (reply_->bytesAvailable ())) < 0)
|
||||
{
|
||||
abort ();
|
||||
Q_EMIT self_->LotW_users_error (tr ("File System Error - Cannot write to file:\n\"%1\"\nError(%2): %3")
|
||||
.arg (csv_file_.fileName ())
|
||||
.arg (csv_file_.error ())
|
||||
.arg (csv_file_.errorString ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void abort ()
|
||||
{
|
||||
lotw_downloader_.abort();
|
||||
if (reply_ && reply_->isRunning ())
|
||||
{
|
||||
reply_->abort ();
|
||||
}
|
||||
}
|
||||
|
||||
// Load the database from the given file name
|
||||
@ -114,14 +222,12 @@ public:
|
||||
auto pos = l.indexOf (',');
|
||||
result[l.left (pos)] = QDate::fromString (l.mid (pos + 1, l.indexOf (',', pos + 1) - pos - 1), "yyyy-MM-dd");
|
||||
}
|
||||
// qDebug () << "LotW User Data Loaded";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error {QObject::tr ("Failed to open LotW users CSV file: '%1'").arg (f.fileName ()).toStdString ()};
|
||||
}
|
||||
LOG_INFO(QString{"LotWUsers: Loaded %1 records from %2"}.arg(result.size()).arg(lotw_csv_file));
|
||||
Q_EMIT self_->progress (QString{"Loaded %1 records from LotW."}.arg(result.size()));
|
||||
Q_EMIT self_->load_finished();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -135,8 +241,6 @@ public:
|
||||
std::future<dictionary> future_load_;
|
||||
dictionary last_uploaded_;
|
||||
qint64 age_constraint_; // days
|
||||
FileDownload lotw_downloader_;
|
||||
bool connected_;
|
||||
};
|
||||
|
||||
#include "LotWUsers.moc"
|
||||
@ -145,7 +249,6 @@ LotWUsers::LotWUsers (QNetworkAccessManager * network_manager, QObject * parent)
|
||||
: QObject {parent}
|
||||
, m_ {this, network_manager}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LotWUsers::~LotWUsers ()
|
||||
|
@ -31,7 +31,6 @@ public:
|
||||
bool user (QString const& call) const;
|
||||
|
||||
Q_SIGNAL void LotW_users_error (QString const& reason) const;
|
||||
Q_SIGNAL void progress (QString const& reason) const;
|
||||
Q_SIGNAL void load_finished () const;
|
||||
|
||||
private:
|
||||
|
@ -71,12 +71,12 @@ public:
|
||||
void heartbeat ();
|
||||
void closedown ();
|
||||
StreamStatus check_status (QDataStream const&) const;
|
||||
void send_message (QByteArray const&, bool queue_if_pending = true, bool allow_duplicates = false);
|
||||
void send_message (QDataStream const& out, QByteArray const& message, bool queue_if_pending = true, bool allow_duplicates = false)
|
||||
void send_message (QByteArray const&, bool queue_if_pending = true);
|
||||
void send_message (QDataStream const& out, QByteArray const& message, bool queue_if_pending = true)
|
||||
{
|
||||
if (OK == check_status (out))
|
||||
{
|
||||
send_message (message, queue_if_pending, allow_duplicates);
|
||||
send_message (message, queue_if_pending);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -137,7 +137,6 @@ void MessageClient::impl::host_info_results (QHostInfo host_info)
|
||||
if (QHostInfo::NoError != host_info.error ())
|
||||
{
|
||||
Q_EMIT self_->error ("UDP server DNS lookup failed: " + host_info.errorString ());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -198,7 +197,7 @@ void MessageClient::impl::start ()
|
||||
// clear any backlog
|
||||
while (pending_messages_.size ())
|
||||
{
|
||||
send_message (pending_messages_.dequeue (), true, false);
|
||||
send_message (pending_messages_.dequeue (), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,7 +429,7 @@ void MessageClient::impl::heartbeat ()
|
||||
out << NetworkMessage::Builder::schema_number // maximum schema number accepted
|
||||
<< version_.toUtf8 () << revision_.toUtf8 ();
|
||||
TRACE_UDP ("schema:" << schema_ << "max schema:" << NetworkMessage::Builder::schema_number << "version:" << version_ << "revision:" << revision_);
|
||||
send_message (out, message, false, true);
|
||||
send_message (out, message, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -445,13 +444,13 @@ void MessageClient::impl::closedown ()
|
||||
}
|
||||
}
|
||||
|
||||
void MessageClient::impl::send_message (QByteArray const& message, bool queue_if_pending, bool allow_duplicates)
|
||||
void MessageClient::impl::send_message (QByteArray const& message, bool queue_if_pending)
|
||||
{
|
||||
if (server_port_)
|
||||
{
|
||||
if (!server_.isNull ())
|
||||
{
|
||||
if (allow_duplicates || message != last_message_) // avoid duplicates
|
||||
if (message != last_message_) // avoid duplicates
|
||||
{
|
||||
if (is_multicast_address (server_))
|
||||
{
|
||||
|
@ -199,7 +199,6 @@
|
||||
* 5 -> WW DIGI
|
||||
* 6 -> FOX
|
||||
* 7 -> HOUND
|
||||
* 8 -> ARRL DIGI
|
||||
*
|
||||
* The Frequency Tolerance and T/R period fields may have a value
|
||||
* of the maximum quint32 value which implies the field is not
|
||||
|
@ -6,8 +6,6 @@
|
||||
//
|
||||
// Reports will be sent in batch mode every 5 minutes.
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
@ -20,7 +18,6 @@
|
||||
#include <QByteArray>
|
||||
#include <QDataStream>
|
||||
#include <QTimer>
|
||||
#include <QDir>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
#include <QRandomGenerator>
|
||||
#endif
|
||||
@ -32,26 +29,19 @@
|
||||
|
||||
#include "moc_PSKReporter.cpp"
|
||||
|
||||
#define DEBUGECLIPSE 0
|
||||
|
||||
namespace
|
||||
{
|
||||
QLatin1String HOST {"report.pskreporter.info"};
|
||||
// QLatin1String HOST {"127.0.0.1"};
|
||||
quint16 SERVICE_PORT {4739};
|
||||
// quint16 SERVICE_PORT {14739};
|
||||
int MIN_SEND_INTERVAL {120}; // in seconds
|
||||
int FLUSH_INTERVAL {MIN_SEND_INTERVAL + 5}; // in send intervals
|
||||
int MIN_SEND_INTERVAL {15}; // in seconds
|
||||
int FLUSH_INTERVAL {4 * 5}; // in send intervals
|
||||
bool ALIGNMENT_PADDING {true};
|
||||
int MIN_PAYLOAD_LENGTH {508};
|
||||
int MAX_PAYLOAD_LENGTH {10000};
|
||||
int CACHE_TIMEOUT {300}; // default to 5 minutes for repeating spots
|
||||
QMap<QString, time_t> spot_cache;
|
||||
int MAX_PAYLOAD_LENGTH {1400};
|
||||
}
|
||||
|
||||
static int added;
|
||||
static int removed;
|
||||
|
||||
class PSKReporter::impl final
|
||||
: public QObject
|
||||
{
|
||||
@ -93,7 +83,6 @@ public:
|
||||
send_receiver_data_ = 3; // three times
|
||||
}
|
||||
});
|
||||
eclipse_load(config->data_dir ().absoluteFilePath ("eclipse.txt"));
|
||||
}
|
||||
|
||||
void check_connection ()
|
||||
@ -178,7 +167,7 @@ public:
|
||||
|
||||
if (!report_timer_.isActive ())
|
||||
{
|
||||
report_timer_.start (MIN_SEND_INTERVAL+1 * 1000); // we add 1 to give some more randomization
|
||||
report_timer_.start (MIN_SEND_INTERVAL * 1000);
|
||||
}
|
||||
if (!descriptor_timer_.isActive ())
|
||||
{
|
||||
@ -199,8 +188,6 @@ public:
|
||||
|
||||
void send_report (bool send_residue = false);
|
||||
void build_preamble (QDataStream&);
|
||||
void eclipse_load(QString filename);
|
||||
bool eclipse_active(QDateTime now = QDateTime::currentDateTime());
|
||||
|
||||
bool flushing ()
|
||||
{
|
||||
@ -209,14 +196,6 @@ public:
|
||||
return flush;
|
||||
}
|
||||
|
||||
QString getStringFromQDateTime(const QString& dateTimeString, const QString& format)
|
||||
{
|
||||
QDateTime dateTime = QDateTime::fromString(dateTimeString, format);
|
||||
return dateTime.toString();
|
||||
}
|
||||
|
||||
QList<QDateTime> eclipseDates;
|
||||
|
||||
logger_type mutable logger_;
|
||||
PSKReporter * self_;
|
||||
Configuration const * config_;
|
||||
@ -293,69 +272,6 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
bool PSKReporter::impl::eclipse_active(QDateTime timeutc)
|
||||
{
|
||||
#ifdef DEBUGECLIPSE
|
||||
std::ofstream mylog("/temp/eclipse.log", std::ios_base::app);
|
||||
#endif
|
||||
QDateTime dateNow = QDateTime::currentDateTimeUtc();
|
||||
for (int i=0; i< eclipseDates.size(); ++i)
|
||||
{
|
||||
QDateTime check = eclipseDates.at(i); // already in UTC time
|
||||
// +- 6 hour window
|
||||
qint64 secondsDiff = qAbs(check.secsTo(dateNow));
|
||||
if (secondsDiff <= 3600*6) // 6 hour check
|
||||
{
|
||||
#ifdef DEBUGECLIPSE
|
||||
mylog << dateNow.toString(Qt::ISODate) << " Eclipse! " << "secondsDiff=" << secondsDiff << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUGECLIPSE
|
||||
mylog << timeutc.toString("yyyy-MM-dd HH:mm:ss") << " no eclipse" << "\n";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void PSKReporter::impl::eclipse_load(QString eclipse_file)
|
||||
{
|
||||
std::ifstream fs(qPrintable(eclipse_file));
|
||||
std::string mydate,mytime,myline;
|
||||
#ifdef DEBUGECLIPSE
|
||||
std::ofstream mylog("c:/temp/eclipse.log");
|
||||
mylog << "eclipse_file=" << eclipse_file << std::endl;
|
||||
#endif
|
||||
if (fs.is_open())
|
||||
{
|
||||
while(!fs.eof())
|
||||
{
|
||||
std::getline(fs, myline);
|
||||
if (myline[0] != '#' && myline.length() > 2) // make sure to skip blank lines
|
||||
{
|
||||
//QString format = "yyyy-MM-dd hh:mm:ss";
|
||||
QDateTime qdate = QDateTime::fromString(QString::fromStdString(myline), Qt::ISODate);
|
||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||
// only add the date if we can cover the whole 12 hours
|
||||
//if (now < qdate.toUTC().addSecs(-3600*6))
|
||||
eclipseDates.append(qdate);
|
||||
#ifdef DEBUGECLIPSE
|
||||
//else
|
||||
// mylog << "not adding " << myline << std::endl;
|
||||
#endif
|
||||
|
||||
}
|
||||
#ifdef DEBUGECLIPSE
|
||||
mylog << myline << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef DEBUGECLIPSE
|
||||
if (eclipse_active(QDateTime::currentDateTime().toUTC())) mylog << "Eclipse is active" << std::endl;
|
||||
else mylog << "Eclipse is not active" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PSKReporter::impl::build_preamble (QDataStream& message)
|
||||
{
|
||||
// Message Header
|
||||
@ -383,7 +299,7 @@ void PSKReporter::impl::build_preamble (QDataStream& message)
|
||||
<< quint16 (0xffff) // Option 1 Field Length (variable)
|
||||
<< quint32 (30351u) // Option 1 Enterprise Number
|
||||
<< quint16 (0x8000 + 5u) // Option 2 Information Element ID (frequency)
|
||||
<< quint16 (5u) // Option 2 Field Length
|
||||
<< quint16 (4u) // Option 2 Field Length
|
||||
<< quint32 (30351u) // Option 2 Enterprise Number
|
||||
<< quint16 (0x8000 + 6u) // Option 3 Information Element ID (sNR)
|
||||
<< quint16 (1u) // Option 3 Field Length
|
||||
@ -507,19 +423,8 @@ void PSKReporter::impl::send_report (bool send_residue)
|
||||
|
||||
// Sender information
|
||||
writeUtfString (tx_out, spot.call_);
|
||||
uint8_t data[5];
|
||||
long long int i64 = spot.freq_;
|
||||
data[0] = ( i64 & 0xff);
|
||||
data[1] = ((i64 >> 8) & 0xff);
|
||||
data[2] = ((i64 >> 16) & 0xff);
|
||||
data[3] = ((i64 >> 24) & 0xff);
|
||||
data[4] = ((i64 >> 32) & 0xff);
|
||||
tx_out // BigEndian
|
||||
<< static_cast<uint8_t> (data[4])
|
||||
<< static_cast<uint8_t> (data[3])
|
||||
<< static_cast<uint8_t> (data[2])
|
||||
<< static_cast<uint8_t> (data[1])
|
||||
<< static_cast<uint8_t> (data[0])
|
||||
tx_out
|
||||
<< static_cast<quint32> (spot.freq_)
|
||||
<< static_cast<qint8> (spot.snr_);
|
||||
writeUtfString (tx_out, spot.mode_);
|
||||
writeUtfString (tx_out, spot.grid_);
|
||||
@ -600,11 +505,6 @@ void PSKReporter::reconnect ()
|
||||
m_->reconnect ();
|
||||
}
|
||||
|
||||
bool PSKReporter::eclipse_active(QDateTime now)
|
||||
{
|
||||
return m_->eclipse_active(now);
|
||||
}
|
||||
|
||||
void PSKReporter::setLocalStation (QString const& call, QString const& gridSquare, QString const& antenna)
|
||||
{
|
||||
LOG_LOG_LOCATION (m_->logger_, trace, "call: " << call << " grid: " << gridSquare << " ant: " << antenna);
|
||||
@ -631,45 +531,7 @@ bool PSKReporter::addRemoteStation (QString const& call, QString const& grid, Ra
|
||||
{
|
||||
reconnect ();
|
||||
}
|
||||
// remove any earlier spots of this call to reduce pskreporter load
|
||||
#ifdef DEBUGPSK
|
||||
static std::fstream fs;
|
||||
if (!fs.is_open()) fs.open("/temp/psk.log", std::fstream::in | std::fstream::out | std::fstream::app);
|
||||
#endif
|
||||
added++;
|
||||
|
||||
QDateTime qdateNow = QDateTime::currentDateTime().toUTC();
|
||||
// we allow all spots through +/- 6 hours around an eclipse for the HamSCI group
|
||||
if (!spot_cache.contains(call) || freq > 49000000 || eclipse_active(qdateNow)) // then it's a new spot
|
||||
{
|
||||
m_->spots_.enqueue ({call, grid, snr, freq, mode, QDateTime::currentDateTimeUtc ()});
|
||||
spot_cache.insert(call, time(NULL));
|
||||
#ifdef DEBUGPSK
|
||||
if (fs.is_open()) fs << "Adding " << call << " freq=" << freq << " " << spot_cache[call] << " count=" << m_->spots_.count() << std::endl;
|
||||
#endif
|
||||
}
|
||||
else if (time(NULL) - spot_cache[call] > CACHE_TIMEOUT) // then the cache has expired
|
||||
{
|
||||
m_->spots_.enqueue ({call, grid, snr, freq, mode, QDateTime::currentDateTimeUtc ()});
|
||||
#ifdef DEBUGPSK
|
||||
if (fs.is_open()) fs << "Adding # " << call << spot_cache[call] << " count=" << m_->spots_.count() << std::endl;
|
||||
#endif
|
||||
spot_cache[call] = time(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
removed++;
|
||||
#ifdef DEBUGPSK
|
||||
if (fs.is_open()) fs << "Removing " << call << " " << time(NULL) << " reduction=" << removed/(double)added*100 << "%" << std::endl;
|
||||
#endif
|
||||
}
|
||||
// remove cached items over 10 minutes old to save a little memory
|
||||
QMapIterator<QString, time_t> i(spot_cache);
|
||||
time_t tmptime = time(NULL);
|
||||
while(i.hasNext()) {
|
||||
i.next();
|
||||
if (tmptime - i.value() > 600) spot_cache.remove(i.key());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -31,10 +31,6 @@ public:
|
||||
//
|
||||
void sendReport (bool last = false);
|
||||
|
||||
//
|
||||
// True if current time falls withing a +/- window of a solar eclipse for HamSCI use
|
||||
bool eclipse_active(QDateTime now);
|
||||
|
||||
Q_SIGNAL void errorOccurred (QString const& reason);
|
||||
|
||||
private:
|
||||
|
@ -278,10 +278,9 @@ QString WSPRNet::encode_mode () const
|
||||
if (m_mode == "FST4W")
|
||||
{
|
||||
auto tr = static_cast<int> ((TR_period_ / 60.)+.5);
|
||||
// if (2 == tr || 15 == tr)
|
||||
if (2 == tr)
|
||||
if (2 == tr || 15 == tr)
|
||||
{
|
||||
tr += 1; // distinguish from WSPR-2
|
||||
tr += 1; // distinguish from WSPR-2 and WSPR-15
|
||||
}
|
||||
return QString::number (tr);
|
||||
}
|
||||
|
51
README
@ -11,30 +11,28 @@
|
||||
|
||||
|
||||
|
||||
Copyright (C) 2001 - 2023 by Joe Taylor, K1JT.
|
||||
Copyright (C) 2001 - 2021 by Joe Taylor, K1JT.
|
||||
|
||||
WSJT-X Version 2.6.1 offers eleven different protocols or modes: FT4,
|
||||
FT8, JT4, JT9, JT65, Q65, FST4, MSK144, WSPR, FST4W, and Echo. The
|
||||
WSJT-X Version 2.3 offers ten different protocols or modes: FT4, FT8,
|
||||
JT4, JT9, JT65, QRA64, FST4, ISCAT, MSK144, WSPR, FST4W, and Echo. The
|
||||
first seven are designed for making reliable QSOs under weak-signal
|
||||
conditions. They use nearly identical message structure and source
|
||||
encoding. JT65 and Q65 were designed for EME (“moonbounce”), but not
|
||||
limited to just that propagation path, on the VHF/UHF bands and JT65
|
||||
has also proven very effective for worldwide QRP communication on the
|
||||
HF bands. Q65 has a number of advantages over JT65, including better
|
||||
performance on the very weakest signals and variants with different
|
||||
T/R period lengths. We imagine that over time it may replace JT65 for
|
||||
EME use, it has also proved to be very effective for iono-scatter
|
||||
paths on 6m. JT9 was originally designed for the LF, MF, and lower HF
|
||||
bands. Its submode JT9A is 2 dB more sensitive than JT65 while using
|
||||
less than 10% of the bandwidth. JT4 offers a wide variety of tone
|
||||
spacings and has proven highly effective for EME on microwave bands up
|
||||
to 24 GHz. These four “slow” modes use one-minute timed sequences of
|
||||
alternating transmission and reception, so a minimal QSO takes four to
|
||||
six minutes — two or three transmissions by each station, one sending
|
||||
in odd UTC minutes and the other even. FT8 is operationally similar
|
||||
but four times faster (15-second T/R sequences) and less sensitive by
|
||||
a few dB. FT4 is faster still (7.5 s T/R sequences) and especially
|
||||
well suited for radio contesting. On the HF bands, world-wide QSOs are
|
||||
encoding. JT65 and QRA64 were designed for EME (“moonbounce”) on the
|
||||
VHF/UHF bands and have also proven very effective for worldwide QRP
|
||||
communication on the HF bands. QRA64 has a number of advantages over
|
||||
JT65, including better performance on the very weakest signals. We
|
||||
imagine that over time it may replace JT65 for EME use. JT9 was
|
||||
originally designed for the LF, MF, and lower HF bands. Its submode
|
||||
JT9A is 2 dB more sensitive than JT65 while using less than 10% of the
|
||||
bandwidth. JT4 offers a wide variety of tone spacings and has proven
|
||||
highly effective for EME on microwave bands up to 24 GHz. These four
|
||||
“slow” modes use one-minute timed sequences of alternating
|
||||
transmission and reception, so a minimal QSO takes four to six minutes
|
||||
— two or three transmissions by each station, one sending in odd UTC
|
||||
minutes and the other even. FT8 is operationally similar but four
|
||||
times faster (15-second T/R sequences) and less sensitive by a few
|
||||
dB. FT4 is faster still (7.5 s T/R sequences) and especially well
|
||||
suited for radio contesting. On the HF bands, world-wide QSOs are
|
||||
possible with any of these modes using power levels of a few watts (or
|
||||
even milliwatts) and compromise antennas. QSOs are possible at signal
|
||||
levels 10 to 15 dB below those required for CW. FST4 has similarities
|
||||
@ -50,13 +48,14 @@ once per transmission. All fast modes in WSJT-X send their message
|
||||
frames repeatedly, as many times as will fit into the Tx sequence
|
||||
length.
|
||||
|
||||
MSK144, and optionally submodes JT9E-H are “fast” protocols designed
|
||||
to take advantage of brief signal enhancements from ionized meteor
|
||||
trails, aircraft scatter, and other types of scatter
|
||||
ISCAT, MSK144, and optionally submodes JT9E-H are “fast” protocols
|
||||
designed to take advantage of brief signal enhancements from ionized
|
||||
meteor trails, aircraft scatter, and other types of scatter
|
||||
propagation. These modes use timed sequences of 5, 10, 15, or 30 s
|
||||
duration. User messages are transmitted repeatedly at high rate (up to
|
||||
250 characters per second, for MSK144) to make good use of the
|
||||
shortest meteor-trail reflections or “pings”. MSK144 uses the same
|
||||
shortest meteor-trail reflections or “pings”. ISCAT uses free-form
|
||||
messages up to 28 characters long, while MSK144 uses the same
|
||||
structured messages as the slow modes and optionally an abbreviated
|
||||
format with hashed callsigns.
|
||||
|
||||
@ -99,7 +98,7 @@ https://wsjtx.groups.io/g/main email reflector.
|
||||
|
||||
Project web site:
|
||||
|
||||
https://wsjt.sourceforge.io/wsjtx.html
|
||||
https://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html
|
||||
|
||||
Project mailing list (shared with other applications from the same
|
||||
team):
|
||||
|
32
Radio.cpp
@ -42,27 +42,14 @@ namespace Radio
|
||||
value = v.toDouble ();
|
||||
if (ok) *ok = true;
|
||||
}
|
||||
if (ok && !*ok)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return frequency (value, scale, ok);
|
||||
}
|
||||
|
||||
Frequency frequency (double value, int scale, bool * ok)
|
||||
{
|
||||
value *= std::pow (10., scale);
|
||||
if (ok)
|
||||
{
|
||||
if (value < 0. || value > static_cast<double>(std::numeric_limits<Frequency>::max ()))
|
||||
if (value < 0. || value > std::numeric_limits<Frequency>::max ())
|
||||
{
|
||||
value = 0.;
|
||||
*ok = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ok = true;
|
||||
}
|
||||
}
|
||||
return std::llround (value);
|
||||
}
|
||||
@ -79,28 +66,15 @@ namespace Radio
|
||||
value = v.toDouble ();
|
||||
if (ok) *ok = true;
|
||||
}
|
||||
if (ok && !*ok)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return frequency_delta (value, scale, ok);
|
||||
}
|
||||
|
||||
FrequencyDelta frequency_delta (double value, int scale, bool * ok)
|
||||
{
|
||||
value *= std::pow (10., scale);
|
||||
if (ok)
|
||||
{
|
||||
if (value < static_cast<double>(std::numeric_limits<Frequency>::min ())
|
||||
|| value > static_cast<double>(std::numeric_limits<Frequency>::max ()))
|
||||
if (value < -std::numeric_limits<Frequency>::max ()
|
||||
|| value > std::numeric_limits<Frequency>::max ())
|
||||
{
|
||||
value = 0.;
|
||||
*ok = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ok = true;
|
||||
}
|
||||
}
|
||||
return std::llround (value);
|
||||
}
|
||||
|
@ -34,12 +34,10 @@ namespace Radio
|
||||
// QVariant argument is convertible to double and is assumed to
|
||||
// be scaled by (10 ** -scale).
|
||||
//
|
||||
Frequency UDP_EXPORT frequency (QVariant const&, int scale = 0,
|
||||
Frequency UDP_EXPORT frequency (QVariant const&, int scale,
|
||||
bool * ok = nullptr, QLocale const& = QLocale ());
|
||||
FrequencyDelta UDP_EXPORT frequency_delta (QVariant const&, int scale = 0,
|
||||
FrequencyDelta UDP_EXPORT frequency_delta (QVariant const&, int scale,
|
||||
bool * ok = nullptr, QLocale const& = QLocale ());
|
||||
Frequency UDP_EXPORT frequency (double, int scale = 0, bool * ok = nullptr);
|
||||
FrequencyDelta UDP_EXPORT frequency_delta (double, int scale = 0, bool * ok = nullptr);
|
||||
|
||||
//
|
||||
// Frequency type formatting
|
||||
|
@ -385,7 +385,7 @@ auto DXLabSuiteCommanderTransceiver::get_mode () -> MODE
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::simple_command (QString const& cmd)
|
||||
{
|
||||
if (!commander_) return;
|
||||
Q_ASSERT (commander_);
|
||||
|
||||
CAT_TRACE (cmd);
|
||||
|
||||
@ -398,7 +398,7 @@ void DXLabSuiteCommanderTransceiver::simple_command (QString const& cmd)
|
||||
|
||||
QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd)
|
||||
{
|
||||
if (!commander_) return QString {};
|
||||
Q_ASSERT (commander_);
|
||||
|
||||
if (!write_to_port (cmd))
|
||||
{
|
||||
@ -437,14 +437,15 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd)
|
||||
};
|
||||
}
|
||||
|
||||
QString result = commander_->readAll ();
|
||||
auto result = commander_->readAll ();
|
||||
// qDebug () << "result: " << result;
|
||||
// for (int i = 0; i < result.size (); ++i)
|
||||
// {
|
||||
// qDebug () << i << ":" << hex << int (result[i]);
|
||||
// }
|
||||
|
||||
if (result != NULL)
|
||||
{
|
||||
CAT_TRACE (cmd << " -> " << QString {result});
|
||||
return result; // converting raw UTF-8 bytes to QString
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool DXLabSuiteCommanderTransceiver::write_to_port (QString const& s)
|
||||
|
@ -18,7 +18,7 @@ namespace
|
||||
|
||||
// some commands require a settling time, particularly "RX A" and
|
||||
// "RX B" on the Yaesu FTdx3000.
|
||||
int constexpr yaesu_delay {350};
|
||||
int constexpr yaesu_delay {250};
|
||||
}
|
||||
|
||||
#include "moc_HRDTransceiver.cpp"
|
||||
@ -1005,7 +1005,7 @@ void HRDTransceiver::do_poll ()
|
||||
|
||||
QString HRDTransceiver::send_command (QString const& cmd, bool prepend_context, bool recurse)
|
||||
{
|
||||
if (!hrd_) return QString {};
|
||||
Q_ASSERT (hrd_);
|
||||
|
||||
QString result;
|
||||
|
||||
@ -1124,7 +1124,7 @@ QByteArray HRDTransceiver::read_reply (QString const& cmd)
|
||||
{
|
||||
// waitForReadReady appears to be occasionally unreliable on Windows
|
||||
// timing out when data is waiting so retry a few times
|
||||
unsigned retries {30};
|
||||
unsigned retries {3};
|
||||
bool replied {false};
|
||||
while (!replied && retries--)
|
||||
{
|
||||
|
@ -659,7 +659,7 @@ int HamlibTransceiver::do_start ()
|
||||
rmode_t mb;
|
||||
pbwidth_t w {RIG_PASSBAND_NORMAL};
|
||||
pbwidth_t wb;
|
||||
if (m_->freq_query_works_ && m_->mode_query_works_
|
||||
if (m_->freq_query_works_
|
||||
&& (!m_->get_vfo_works_ || !rig_get_function_ptr (m_->model_, RIG_FUNCTION_GET_VFO)))
|
||||
{
|
||||
// Icom have deficient CAT protocol with no way of reading which
|
||||
@ -760,7 +760,7 @@ int HamlibTransceiver::do_start ()
|
||||
|
||||
m_->reversed_ = RIG_VFO_B == v;
|
||||
|
||||
if (m_->mode_query_works_ && !(rig_get_caps_int (m_->model_, RIG_CAPS_TARGETABLE_VFO) & RIG_TARGETABLE_MODE))
|
||||
if (m_->mode_query_works_ && !(rig_get_caps_int (m_->model_, RIG_CAPS_TARGETABLE_VFO) & (RIG_TARGETABLE_MODE | RIG_TARGETABLE_PURE)))
|
||||
{
|
||||
if (RIG_OK == rig_get_mode (m_->rig_.data (), RIG_VFO_CURR, &m, &w))
|
||||
{
|
||||
@ -882,12 +882,7 @@ void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
|
||||
{
|
||||
// for the 1st time as a band change may cause a recalled mode to be
|
||||
// set
|
||||
vfo_t target_vfo = RIG_VFO_CURR;
|
||||
if (!(m_->rig_->state.vfo_list & RIG_VFO_B))
|
||||
{
|
||||
target_vfo = RIG_VFO_MAIN; // no VFO A/B so force to Rx on MAIN
|
||||
}
|
||||
m_->error_check (rig_set_freq (m_->rig_.data (), target_vfo, f), tr ("setting frequency"));
|
||||
m_->error_check (rig_set_freq (m_->rig_.data (), RIG_VFO_CURR, f), tr ("setting frequency"));
|
||||
update_rx_frequency (f);
|
||||
|
||||
if (m_->mode_query_works_ && UNK != m)
|
||||
@ -895,13 +890,13 @@ void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
|
||||
rmode_t current_mode;
|
||||
pbwidth_t current_width;
|
||||
auto new_mode = m_->map_mode (m);
|
||||
m_->error_check (rig_get_mode (m_->rig_.data (), target_vfo, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
m_->error_check (rig_get_mode (m_->rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
CAT_TRACE ("rig_get_mode mode=" << rig_strrmode (current_mode) << " bw=" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode));
|
||||
m_->error_check (rig_set_mode (m_->rig_.data (), target_vfo, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
m_->error_check (rig_set_mode (m_->rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
|
||||
// for the 2nd time because a mode change may have caused a
|
||||
// frequency change
|
||||
@ -910,10 +905,8 @@ void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
|
||||
// for the second time because some rigs change mode according
|
||||
// to frequency such as the TS-2000 auto mode setting
|
||||
CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode));
|
||||
m_->error_check (rig_set_mode (m_->rig_.data (), target_vfo, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
m_->error_check (rig_set_mode (m_->rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
}
|
||||
// set mode on VFOB too if we are in split
|
||||
if (state ().split()) rig_set_mode (m_->rig_.data (), RIG_VFO_B, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting VFOB mode");
|
||||
update_mode (m);
|
||||
}
|
||||
}
|
||||
@ -1044,22 +1037,16 @@ void HamlibTransceiver::do_mode (MODE mode)
|
||||
pbwidth_t current_width;
|
||||
auto new_mode = m_->map_mode (mode);
|
||||
|
||||
vfo_t target_vfo = RIG_VFO_CURR;
|
||||
if (!(m_->rig_->state.vfo_list & RIG_VFO_B))
|
||||
{
|
||||
target_vfo = RIG_VFO_MAIN; // no VFO A/B so force to Rx on MAIN
|
||||
}
|
||||
|
||||
// only change when receiving or simplex if direct VFO addressing unavailable
|
||||
if (!(state ().ptt () && state ().split () && m_->one_VFO_))
|
||||
{
|
||||
m_->error_check (rig_get_mode (m_->rig_.data (), target_vfo, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
m_->error_check (rig_get_mode (m_->rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
CAT_TRACE ("rig_get_mode mode=" << rig_strrmode (current_mode) << " bw=" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
CAT_TRACE ("rig_set_mode mode=" << rig_strrmode (new_mode));
|
||||
m_->error_check (rig_set_mode (m_->rig_.data (), target_vfo, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
m_->error_check (rig_set_mode (m_->rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NOCHANGE), tr ("setting current VFO mode"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1141,13 +1128,13 @@ void HamlibTransceiver::do_poll ()
|
||||
{
|
||||
m_->error_check (rig_get_freq (m_->rig_.data (), RIG_VFO_CURR, &f), tr ("getting current VFO frequency"));
|
||||
f = std::round (f);
|
||||
CAT_TRACE ("rig_get_freq frequency=" << Radio::frequency (f));
|
||||
CAT_TRACE ("rig_get_freq frequency=" << f);
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
|
||||
if ((WSJT_RIG_NONE_CAN_SPLIT || !m_->is_dummy_)
|
||||
&& state ().split ()
|
||||
&& (rig_get_caps_int (m_->model_, RIG_CAPS_TARGETABLE_VFO) & RIG_TARGETABLE_FREQ)
|
||||
&& (rig_get_caps_int (m_->model_, RIG_CAPS_TARGETABLE_VFO) & (RIG_TARGETABLE_FREQ | RIG_TARGETABLE_PURE))
|
||||
&& !m_->one_VFO_)
|
||||
{
|
||||
// only read "other" VFO if in split, this allows rigs like
|
||||
|
@ -96,11 +96,11 @@ void OmniRigTransceiver::register_transceivers (logger_type *,
|
||||
};
|
||||
}
|
||||
|
||||
OmniRigTransceiver::OmniRigTransceiver (logger_type * the_logger,
|
||||
OmniRigTransceiver::OmniRigTransceiver (logger_type * logger,
|
||||
std::unique_ptr<TransceiverBase> wrapped,
|
||||
RigNumber n, TransceiverFactory::PTTMethod ptt_type,
|
||||
QString const& ptt_port, QObject * parent)
|
||||
: TransceiverBase {the_logger, parent}
|
||||
: TransceiverBase {logger, parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, use_for_ptt_ {TransceiverFactory::PTT_method_CAT == ptt_type || ("CAT" == ptt_port && (TransceiverFactory::PTT_method_RTS == ptt_type || TransceiverFactory::PTT_method_DTR == ptt_type))}
|
||||
, ptt_type_ {ptt_type}
|
||||
@ -111,20 +111,26 @@ OmniRigTransceiver::OmniRigTransceiver (logger_type * the_logger,
|
||||
, reversed_ {false}
|
||||
{
|
||||
CoInitializeEx (nullptr, 0 /*COINIT_APARTMENTTHREADED*/); // required because Qt only does this for GUI thread
|
||||
CAT_TRACE ("constructed");
|
||||
}
|
||||
|
||||
OmniRigTransceiver::~OmniRigTransceiver ()
|
||||
{
|
||||
CAT_TRACE ("destroying");
|
||||
CoUninitialize ();
|
||||
}
|
||||
|
||||
// returns false on time out
|
||||
bool OmniRigTransceiver::await_notification_with_timeout (int timeout)
|
||||
{
|
||||
QEventLoop el;
|
||||
connect (this, &OmniRigTransceiver::notified, &el, [&el] () {el.exit (1);});
|
||||
QTimer::singleShot (timeout, Qt::CoarseTimer, &el, [&el] () {el.exit (0);});
|
||||
return 1 == el.exec (); // wait for notify or timer
|
||||
}
|
||||
|
||||
int OmniRigTransceiver::do_start ()
|
||||
{
|
||||
CAT_TRACE ("starting");
|
||||
try
|
||||
{
|
||||
|
||||
if (wrapped_) wrapped_->start (0);
|
||||
|
||||
omni_rig_.reset (new OmniRig::OmniRigX {this});
|
||||
@ -146,10 +152,8 @@ int OmniRigTransceiver::do_start ()
|
||||
, SIGNAL (CustomReply (int, QVariant const&, QVariant const&))
|
||||
, this, SLOT (handle_custom_reply (int, QVariant const&, QVariant const&)));
|
||||
|
||||
CAT_INFO ("OmniRig s/w version: " << static_cast<quint16> (omni_rig_->SoftwareVersion () >> 16)
|
||||
<< '.' << static_cast<quint16> (omni_rig_->SoftwareVersion () & 0xffff)
|
||||
<< " i/f version: " << static_cast<int> (omni_rig_->InterfaceVersion () >> 8 & 0xff)
|
||||
<< '.' << static_cast<int> (omni_rig_->InterfaceVersion () && 0xff));
|
||||
CAT_INFO ("OmniRig s/w version: " << omni_rig_->SoftwareVersion ()
|
||||
<< "i/f version: " << omni_rig_->InterfaceVersion ());
|
||||
|
||||
// fetch the interface of the RigX CoClass and instantiate a proxy object
|
||||
switch (rig_number_)
|
||||
@ -164,26 +168,12 @@ int OmniRigTransceiver::do_start ()
|
||||
// COM/OLE exceptions get signaled
|
||||
connect (&*rig_, SIGNAL (exception (int, QString, QString, QString)), this, SLOT (handle_COM_exception (int, QString, QString, QString)));
|
||||
|
||||
offline_timer_.reset (new QTimer); // instantiate here as constructor runs in wrong thread
|
||||
offline_timer_.reset (new QTimer); // instantiate here as
|
||||
// constructor runs in wrong
|
||||
// thread
|
||||
offline_timer_->setSingleShot (true);
|
||||
connect (offline_timer_.data (), &QTimer::timeout, [this] () {offline ("Rig went offline");});
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
// leave some time for Omni-Rig to do its first poll
|
||||
QThread::msleep (250);
|
||||
if (OmniRig::ST_ONLINE == rig_->Status ())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (OmniRig::ST_ONLINE != rig_->Status ())
|
||||
{
|
||||
CAT_ERROR ("rig not online");
|
||||
throw_qstring ("OmniRig: " + rig_->StatusStr ());
|
||||
}
|
||||
|
||||
if (use_for_ptt_ && (TransceiverFactory::PTT_method_DTR == ptt_type_ || TransceiverFactory::PTT_method_RTS == ptt_type_))
|
||||
{
|
||||
// fetch the interface for the serial port if we need it for PTT
|
||||
@ -223,7 +213,27 @@ int OmniRigTransceiver::do_start ()
|
||||
.arg (readable_params_, 8, 16, QChar ('0'))
|
||||
.arg (writable_params_, 8, 16, QChar ('0'))
|
||||
.arg (rig_number_));
|
||||
update_rx_frequency (rig_->GetRxFrequency ());
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
if (OmniRig::ST_ONLINE == rig_->Status ())
|
||||
{
|
||||
break;
|
||||
}
|
||||
await_notification_with_timeout (1000);
|
||||
}
|
||||
if (OmniRig::ST_ONLINE != rig_->Status ())
|
||||
{
|
||||
throw_qstring ("OmniRig: " + rig_->StatusStr ());
|
||||
}
|
||||
QThread::msleep (500); // leave some time for Omni-Rig to get
|
||||
// the rig status for the 1st. time
|
||||
auto f = rig_->GetRxFrequency ();
|
||||
for (int i = 0; (f == 0) && (i < 5); ++i)
|
||||
{
|
||||
await_notification_with_timeout (1000);
|
||||
f = rig_->GetRxFrequency ();
|
||||
}
|
||||
update_rx_frequency (f);
|
||||
int resolution {0};
|
||||
if (OmniRig::PM_UNKNOWN == rig_->Vfo ()
|
||||
&& (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
|
||||
@ -233,7 +243,7 @@ int OmniRigTransceiver::do_start ()
|
||||
// can't query VFO but can set explicitly
|
||||
rig_->SetVfo (OmniRig::PM_VFOA);
|
||||
}
|
||||
auto f = state ().frequency ();
|
||||
f = state ().frequency ();
|
||||
if (f % 10) return resolution; // 1Hz resolution
|
||||
auto test_frequency = f - f % 100 + 55;
|
||||
if (OmniRig::PM_FREQ & writable_params_)
|
||||
@ -252,6 +262,11 @@ int OmniRigTransceiver::do_start ()
|
||||
{
|
||||
throw_qstring (tr ("OmniRig: don't know how to set rig frequency"));
|
||||
}
|
||||
if (!await_notification_with_timeout (1000))
|
||||
{
|
||||
CAT_ERROR ("do_start 1: wait timed out");
|
||||
throw_qstring (tr ("OmniRig: timeout waiting for update from rig"));
|
||||
}
|
||||
switch (rig_->GetRxFrequency () - test_frequency)
|
||||
{
|
||||
case -5: resolution = -1; break; // 10Hz truncated
|
||||
@ -275,51 +290,34 @@ int OmniRigTransceiver::do_start ()
|
||||
{
|
||||
rig_->SetFreqA (test_frequency);
|
||||
}
|
||||
if (!await_notification_with_timeout (2000))
|
||||
{
|
||||
CAT_ERROR ("do_start 2: wait timed out");
|
||||
throw_qstring (tr ("OmniRig: timeout waiting for update from rig"));
|
||||
}
|
||||
if (9 == rig_->GetRxFrequency () - test_frequency)
|
||||
{
|
||||
resolution = 2; // 20Hz rounded
|
||||
}
|
||||
}
|
||||
|
||||
// For OmniRig v1.19 or later we need a delay between GetRxFrequency () and SetFreq (f),
|
||||
// otherwise rig QRG stays at f+55 Hz. 200 ms should do job for all modern transceivers.
|
||||
// However, with very slow rigs, QRG may still stay at f+55 Hz. Such rigs should use v1.18.
|
||||
// Due to the asynchronous nature of Omnirig commands, a better solution would be to implement
|
||||
// an event handler for OmniRig's OnParamChange event and read the frequency inside that handler.
|
||||
|
||||
if (OmniRig::PM_FREQ & writable_params_)
|
||||
{
|
||||
QTimer::singleShot (200, [=] {
|
||||
rig_->SetFreq (f);
|
||||
});
|
||||
}
|
||||
else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
|
||||
{
|
||||
QTimer::singleShot (200, [=] {
|
||||
rig_->SetFreqB (f);
|
||||
});
|
||||
}
|
||||
else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
|
||||
{
|
||||
QTimer::singleShot (200, [=] {
|
||||
rig_->SetFreqA (f);
|
||||
});
|
||||
}
|
||||
update_rx_frequency (f);
|
||||
CAT_TRACE ("started");
|
||||
|
||||
return resolution;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CAT_TRACE ("start threw exception");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_stop ()
|
||||
{
|
||||
CAT_TRACE ("stopping");
|
||||
QThread::msleep (200); // leave some time for pending
|
||||
// commands at the server end
|
||||
|
||||
@ -339,7 +337,6 @@ void OmniRigTransceiver::do_stop ()
|
||||
{
|
||||
rig_->clear ();
|
||||
rig_.reset ();
|
||||
CAT_TRACE ("rig_ reset");
|
||||
}
|
||||
omni_rig_->clear ();
|
||||
omni_rig_.reset ();
|
||||
@ -399,6 +396,7 @@ void OmniRigTransceiver::handle_status_change (int rig_number)
|
||||
else
|
||||
{
|
||||
offline_timer_->stop (); // good to go again
|
||||
Q_EMIT notified ();
|
||||
}
|
||||
// else
|
||||
// {
|
||||
@ -469,6 +467,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
|
||||
if (params & OmniRig::PM_FREQ)
|
||||
{
|
||||
CAT_TRACE ("FREQ");
|
||||
need_frequency = true;
|
||||
}
|
||||
if (params & OmniRig::PM_FREQA)
|
||||
@ -654,6 +653,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
}
|
||||
CAT_TRACE ("OmniRig params change: state after:" << state ());
|
||||
}
|
||||
Q_EMIT notified ();
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& command, QVariant const& reply)
|
||||
@ -710,7 +710,7 @@ void OmniRigTransceiver::do_ptt (bool on)
|
||||
|
||||
void OmniRigTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
CAT_TRACE (f << ' ' << state ());
|
||||
CAT_TRACE (f << state ());
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
if (UNK != m)
|
||||
{
|
||||
@ -739,7 +739,7 @@ void OmniRigTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
|
||||
void OmniRigTransceiver::do_tx_frequency (Frequency tx, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
CAT_TRACE (tx << ' ' << state ());
|
||||
CAT_TRACE (tx << state ());
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
bool split {tx != 0};
|
||||
if (split)
|
||||
@ -804,7 +804,7 @@ void OmniRigTransceiver::do_tx_frequency (Frequency tx, MODE m, bool /*no_ignore
|
||||
|
||||
void OmniRigTransceiver::do_mode (MODE mode)
|
||||
{
|
||||
CAT_TRACE (mode << ' ' << state ());
|
||||
CAT_TRACE (mode << state ());
|
||||
if (!rig_ || rig_->isNull ()) return;
|
||||
// TODO: G4WJS OmniRig doesn't seem to have any capability of tracking/setting VFO B mode
|
||||
auto mapped = map_mode (mode);
|
||||
|
@ -44,6 +44,9 @@ public:
|
||||
void do_ptt (bool on) override;
|
||||
|
||||
private:
|
||||
bool await_notification_with_timeout (int timeout);
|
||||
Q_SIGNAL void notified () const;
|
||||
// Q_SLOT void timeout_check ();
|
||||
Q_SLOT void handle_COM_exception (int, QString, QString, QString);
|
||||
Q_SLOT void handle_visible_change ();
|
||||
Q_SLOT void handle_rig_type_change (int rig_number);
|
||||
|
@ -117,10 +117,6 @@ void PollingTransceiver::do_post_ptt (bool p)
|
||||
retries_ = polls_to_stabilize;
|
||||
//retries_ = 0; // fast feedback on PTT
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state_.ptt(p); // ensure this is initialized
|
||||
}
|
||||
}
|
||||
|
||||
bool PollingTransceiver::do_pre_update ()
|
||||
|
@ -23,12 +23,6 @@ QDebug operator << (QDebug d, Transceiver::TransceiverState const& s)
|
||||
}
|
||||
#endif
|
||||
|
||||
std::ostream& operator << (std::ostream& os, Transceiver::MODE m)
|
||||
{
|
||||
auto const& mo = Transceiver::staticMetaObject; \
|
||||
return os << mo.enumerator (mo.indexOfEnumerator ("MODE")).valueToKey (static_cast<int> (m)); \
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, Transceiver::TransceiverState const& s)
|
||||
{
|
||||
return os
|
||||
|
@ -169,7 +169,6 @@ Q_DECLARE_METATYPE (Transceiver::TransceiverState);
|
||||
QDebug operator << (QDebug, Transceiver::TransceiverState const&);
|
||||
#endif
|
||||
|
||||
std::ostream& operator << (std::ostream&, Transceiver::MODE);
|
||||
std::ostream& operator << (std::ostream&, Transceiver::TransceiverState const&);
|
||||
|
||||
ENUM_QDATASTREAM_OPS_DECL (Transceiver, MODE);
|
||||
|
@ -16,8 +16,6 @@ namespace
|
||||
|
||||
void TransceiverBase::start (unsigned sequence_number) noexcept
|
||||
{
|
||||
CAT_TRACE ("#: " << sequence_number);
|
||||
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
@ -28,12 +26,10 @@ void TransceiverBase::start (unsigned sequence_number) noexcept
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
CAT_TRACE ("#: " << sequence_number << " what: " << e.what ());
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CAT_TRACE ("#: " << sequence_number);
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
@ -45,7 +41,7 @@ void TransceiverBase::start (unsigned sequence_number) noexcept
|
||||
void TransceiverBase::set (TransceiverState const& s,
|
||||
unsigned sequence_number) noexcept
|
||||
{
|
||||
CAT_TRACE ("#: " << s);
|
||||
CAT_TRACE ("#: " << sequence_number << " " << s);
|
||||
|
||||
QString message;
|
||||
try
|
||||
@ -81,7 +77,8 @@ void TransceiverBase::set (TransceiverState const& s,
|
||||
}
|
||||
if (s.frequency () // ignore bogus zero frequencies
|
||||
&& ((s.frequency () != requested_.frequency () // and QSY
|
||||
|| (s.mode () != UNK && s.mode () != requested_.mode ())))) // or mode change
|
||||
|| (s.mode () != UNK && s.mode () != requested_.mode ())) // or mode change
|
||||
|| ptt_off)) // or just returned to rx
|
||||
{
|
||||
do_frequency (s.frequency (), s.mode (), ptt_off);
|
||||
do_post_frequency (s.frequency (), s.mode ());
|
||||
@ -122,12 +119,10 @@ void TransceiverBase::set (TransceiverState const& s,
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
CAT_TRACE ("#: " << sequence_number << " what: " << e.what ());
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CAT_TRACE ("#: " << sequence_number << " " << sequence_number);
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
@ -138,7 +133,6 @@ void TransceiverBase::set (TransceiverState const& s,
|
||||
|
||||
void TransceiverBase::startup ()
|
||||
{
|
||||
CAT_TRACE ("startup");
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
@ -150,12 +144,10 @@ void TransceiverBase::startup ()
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
CAT_TRACE ("startup" << " what: " << e.what ());
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CAT_TRACE ("startup");
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
@ -166,7 +158,6 @@ void TransceiverBase::startup ()
|
||||
|
||||
void TransceiverBase::shutdown ()
|
||||
{
|
||||
CAT_TRACE ("shutdown");
|
||||
may_update u {this};
|
||||
if (requested_.online ())
|
||||
{
|
||||
@ -186,7 +177,6 @@ void TransceiverBase::shutdown ()
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CAT_TRACE ("shutdown");
|
||||
// don't care about exceptions
|
||||
}
|
||||
}
|
||||
@ -196,7 +186,6 @@ void TransceiverBase::shutdown ()
|
||||
|
||||
void TransceiverBase::stop () noexcept
|
||||
{
|
||||
CAT_TRACE ("stop");
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
@ -204,12 +193,10 @@ void TransceiverBase::stop () noexcept
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
CAT_TRACE ("stop" << " what: " << e.what ());
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CAT_TRACE ("stop");
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
@ -224,7 +211,6 @@ void TransceiverBase::stop () noexcept
|
||||
|
||||
void TransceiverBase::update_rx_frequency (Frequency rx)
|
||||
{
|
||||
CAT_TRACE ("frequency: " << rx);
|
||||
if (rx)
|
||||
{
|
||||
actual_.frequency (rx);
|
||||
@ -234,35 +220,28 @@ void TransceiverBase::update_rx_frequency (Frequency rx)
|
||||
|
||||
void TransceiverBase::update_other_frequency (Frequency tx)
|
||||
{
|
||||
CAT_TRACE ("frequency: " << tx);
|
||||
actual_.tx_frequency (tx);
|
||||
}
|
||||
|
||||
void TransceiverBase::update_split (bool state)
|
||||
{
|
||||
CAT_TRACE ("state: " << state);
|
||||
actual_.split (state);
|
||||
}
|
||||
|
||||
void TransceiverBase::update_mode (MODE m)
|
||||
{
|
||||
CAT_TRACE ("mode: " << m);
|
||||
actual_.mode (m);
|
||||
requested_.mode (m); // track rig changes
|
||||
}
|
||||
|
||||
void TransceiverBase::update_PTT (bool state)
|
||||
{
|
||||
CAT_TRACE ("state: " << state);
|
||||
actual_.ptt (state);
|
||||
}
|
||||
|
||||
void TransceiverBase::update_complete (bool force_signal)
|
||||
{
|
||||
CAT_TRACE ("force signal: " << force_signal);
|
||||
if ((do_pre_update ()
|
||||
&& actual_ != last_)
|
||||
|| force_signal)
|
||||
if ((do_pre_update () && actual_ != last_) || force_signal)
|
||||
{
|
||||
Q_EMIT update (actual_, last_sequence_number_);
|
||||
last_ = actual_;
|
||||
@ -271,7 +250,6 @@ void TransceiverBase::update_complete (bool force_signal)
|
||||
|
||||
void TransceiverBase::offline (QString const& reason)
|
||||
{
|
||||
CAT_TRACE ("reason: " << reason);
|
||||
Q_EMIT failure (reason);
|
||||
try
|
||||
{
|
||||
@ -279,7 +257,6 @@ void TransceiverBase::offline (QString const& reason)
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CAT_TRACE ("reason: " << reason);
|
||||
// don't care
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
// menu that allows each dock window to be hidden or revealed.
|
||||
//
|
||||
|
||||
#include <locale>
|
||||
#include <clocale>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
@ -52,9 +52,10 @@ int main (int argc, char * argv[])
|
||||
QApplication app {argc, argv};
|
||||
try
|
||||
{
|
||||
// ensure number forms are in consistent format, do this after
|
||||
// instantiating QApplication so that GUI has correct l18n
|
||||
std::locale::global (std::locale::classic ());
|
||||
setlocale (LC_NUMERIC, "C"); // ensure number forms are in
|
||||
// consistent format, do this after
|
||||
// instantiating QApplication so
|
||||
// that GUI has correct l18n
|
||||
|
||||
app.setApplicationName ("WSJT-X Reference UDP Message Aggregator Server");
|
||||
app.setApplicationVersion ("1.0");
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <locale>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <QCoreApplication>
|
||||
@ -264,9 +263,10 @@ int main (int argc, char * argv[])
|
||||
QCoreApplication app {argc, argv};
|
||||
try
|
||||
{
|
||||
// ensure number forms are in consistent format, do this after
|
||||
// instantiating QApplication so that GUI has correct l18n
|
||||
std::locale::global (std::locale::classic ());
|
||||
setlocale (LC_NUMERIC, "C"); // ensure number forms are in
|
||||
// consistent format, do this after
|
||||
// instantiating QApplication so
|
||||
// that GUI has correct l18n
|
||||
|
||||
app.setApplicationName ("WSJT-X UDP Message Server Daemon");
|
||||
app.setApplicationVersion ("1.0");
|
||||
|
149
WSJTXLogging.cpp
@ -93,7 +93,7 @@ namespace
|
||||
<< boost::log::add_value ("Line", context.line)
|
||||
<< boost::log::add_value ("File", file)
|
||||
<< boost::log::add_value ("Function", function)
|
||||
<< msg.toStdString ();
|
||||
<< msg.toStdWString ();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -101,80 +101,9 @@ namespace
|
||||
<< boost::log::add_value ("Line", context.line)
|
||||
<< boost::log::add_value ("File", file)
|
||||
<< boost::log::add_value ("Function", function)
|
||||
<< context.category << ": " << msg.toStdString ();
|
||||
<< context.category << ": " << msg.toStdWString ();
|
||||
}
|
||||
}
|
||||
|
||||
void default_log_config ()
|
||||
{
|
||||
auto core = logging::core::get ();
|
||||
|
||||
//
|
||||
// Define sinks, filters, and formatters using expression
|
||||
// templates for efficiency.
|
||||
//
|
||||
|
||||
// Default log file location.
|
||||
QDir app_data {QStandardPaths::writableLocation (QStandardPaths::AppLocalDataLocation)};
|
||||
Logger::init (); // Basic setup of attributes
|
||||
|
||||
//
|
||||
// Sink intended for general use that passes everything above
|
||||
// selected severity levels per channel. Log file is appended
|
||||
// between sessions and rotated to limit storage space usage.
|
||||
//
|
||||
auto sys_sink = boost::make_shared<sinks::asynchronous_sink<sinks::text_file_backend>>
|
||||
(
|
||||
keywords::auto_flush = false
|
||||
#if BOOST_VERSION / 100 >= 1070
|
||||
, keywords::file_name = app_data.absoluteFilePath ("wsjtx_syslog.log").toStdWString ()
|
||||
, keywords::target_file_name =
|
||||
#else
|
||||
, keywords::file_name =
|
||||
#endif
|
||||
app_data.absoluteFilePath ("logs/wsjtx_syslog_%Y-%m.log").toStdWString ()
|
||||
, keywords::time_based_rotation = sinks::file::rotation_at_time_point (gregorian::greg_day (1), 0, 0, 0)
|
||||
, keywords::open_mode = std::ios_base::out | std::ios_base::app
|
||||
#if BOOST_VERSION / 100 >= 1063
|
||||
, keywords::enable_final_rotation = false
|
||||
#endif
|
||||
);
|
||||
|
||||
sys_sink->locked_backend ()->set_file_collector
|
||||
(
|
||||
sinks::file::make_collector
|
||||
(
|
||||
keywords::max_size = 5 * 1024 * 1024
|
||||
, keywords::min_free_space = 1024 * 1024 * 1024
|
||||
, keywords::max_files = 12
|
||||
, keywords::target = app_data.absoluteFilePath ("logs").toStdWString ()
|
||||
)
|
||||
);
|
||||
sys_sink->locked_backend ()->scan_for_files ();
|
||||
|
||||
// Per channel severity level filter
|
||||
using min_severity_filter = expr::channel_severity_filter_actor<std::string, trivial::severity_level>;
|
||||
min_severity_filter min_severity = expr::channel_severity_filter (channel, severity);
|
||||
min_severity["SYSLOG"] = trivial::info;
|
||||
min_severity["RIGCTRL"] = trivial::info;
|
||||
min_severity["DATALOG"] = trivial::info;
|
||||
sys_sink->set_filter (min_severity || severity >= trivial::fatal);
|
||||
|
||||
sys_sink->set_formatter
|
||||
(
|
||||
expr::stream
|
||||
<< "[" << channel
|
||||
<< "][" << expr::format_date_time<posix_time::ptime> ("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
|
||||
<< "][" << expr::format_date_time<posix_time::time_duration> ("Uptime", "%O:%M:%S.%f")
|
||||
<< "][" << trivial::severity
|
||||
<< "] " << expr::message
|
||||
);
|
||||
|
||||
core->add_sink (sys_sink);
|
||||
|
||||
// Indicate start of logging
|
||||
LOG_INFO ("Log Start");
|
||||
}
|
||||
}
|
||||
|
||||
WSJTXLogging::WSJTXLogging ()
|
||||
@ -223,23 +152,77 @@ WSJTXLogging::WSJTXLogging ()
|
||||
new_config += config.mid (pos);
|
||||
std::wstringbuf buffer {new_config.toStdWString (), std::ios_base::in};
|
||||
std::wistream stream {&buffer};
|
||||
try
|
||||
{
|
||||
Logger::init_from_config (stream);
|
||||
LOG_INFO ("Read logging configuration file: " << log_config.fileName ());
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
default_log_config ();
|
||||
LOG_ERROR ("Reading logging configuration file: " << log_config.fileName () << " - " << e.what ());
|
||||
LOG_INFO ("Reverting to default logging configuration");
|
||||
}
|
||||
}
|
||||
else // Default setup
|
||||
{
|
||||
default_log_config ();
|
||||
//
|
||||
// Define sinks, filters, and formatters using expression
|
||||
// templates for efficiency.
|
||||
//
|
||||
|
||||
// Default log file location.
|
||||
QDir app_data {QStandardPaths::writableLocation (QStandardPaths::AppLocalDataLocation)};
|
||||
Logger::init (); // Basic setup of attributes
|
||||
|
||||
//
|
||||
// Sink intended for general use that passes everything above
|
||||
// selected severity levels per channel. Log file is appended
|
||||
// between sessions and rotated to limit storage space usage.
|
||||
//
|
||||
auto sys_sink = boost::make_shared<sinks::asynchronous_sink<sinks::text_file_backend>>
|
||||
(
|
||||
keywords::auto_flush = false
|
||||
#if BOOST_VERSION / 100 >= 1070
|
||||
, keywords::file_name = app_data.absoluteFilePath ("wsjtx_syslog.log").toStdWString ()
|
||||
, keywords::target_file_name =
|
||||
#else
|
||||
, keywords::file_name =
|
||||
#endif
|
||||
app_data.absoluteFilePath ("logs/wsjtx_syslog_%Y-%m.log").toStdString ()
|
||||
, keywords::time_based_rotation = sinks::file::rotation_at_time_point (gregorian::greg_day (1), 0, 0, 0)
|
||||
, keywords::open_mode = std::ios_base::out | std::ios_base::app
|
||||
#if BOOST_VERSION / 100 >= 1063
|
||||
, keywords::enable_final_rotation = false
|
||||
#endif
|
||||
);
|
||||
|
||||
sys_sink->locked_backend ()->set_file_collector
|
||||
(
|
||||
sinks::file::make_collector
|
||||
(
|
||||
keywords::max_size = 5 * 1024 * 1024
|
||||
, keywords::min_free_space = 1024 * 1024 * 1024
|
||||
, keywords::max_files = 12
|
||||
, keywords::target = app_data.absoluteFilePath ("logs").toStdWString ()
|
||||
)
|
||||
);
|
||||
sys_sink->locked_backend ()->scan_for_files ();
|
||||
|
||||
// Per channel severity level filter
|
||||
using min_severity_filter = expr::channel_severity_filter_actor<std::string, trivial::severity_level>;
|
||||
min_severity_filter min_severity = expr::channel_severity_filter (channel, severity);
|
||||
min_severity["SYSLOG"] = trivial::info;
|
||||
min_severity["RIGCTRL"] = trivial::info;
|
||||
min_severity["DATALOG"] = trivial::info;
|
||||
sys_sink->set_filter (min_severity || severity >= trivial::fatal);
|
||||
|
||||
sys_sink->set_formatter
|
||||
(
|
||||
expr::stream
|
||||
<< "[" << channel
|
||||
<< "][" << expr::format_date_time<posix_time::ptime> ("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
|
||||
<< "][" << expr::format_date_time<posix_time::time_duration> ("Uptime", "%O:%M:%S.%f")
|
||||
<< "][" << trivial::severity
|
||||
<< "] " << expr::message
|
||||
);
|
||||
|
||||
core->add_sink (sys_sink);
|
||||
}
|
||||
|
||||
// Indicate start of logging
|
||||
LOG_INFO ("Log Start");
|
||||
::qInstallMessageHandler (&qt_log_handler);
|
||||
}
|
||||
|
||||
|
@ -473,6 +473,7 @@ auto WSPRBandHopping::next_hop (bool tx_enabled) -> Hop
|
||||
|
||||
, frequencies_index >= 0 // new band
|
||||
&& tx_enabled // transmit is allowed
|
||||
&& !tx_next // not going to Tx anyway
|
||||
&& m_->bands_[4].testBit (band_index) // tune up required
|
||||
&& !m_->bands_[5].testBit (band_index) // not an Rx only band
|
||||
|
||||
|
@ -24,8 +24,7 @@ class QWidget;
|
||||
//
|
||||
// Along with selecting bands a flag indicating that a short tune up
|
||||
// signal is required for specified bands before they are used for
|
||||
// transmit or receive, unless they are flagged as Rx Only (intended
|
||||
// to protect Rx active aerials and non-licensed bands).
|
||||
// receive.
|
||||
//
|
||||
// Provides a Qt property that holds the Tx percentage which is used
|
||||
// to generate a semi-randomized schedule of period to transmit. This
|
||||
@ -41,7 +40,7 @@ class QWidget;
|
||||
// storage using the provided QSettings object instance.
|
||||
//
|
||||
// A passed in Configuration object instance is used to query the
|
||||
// FrequencyList_v2_101 model to determine working frequencies for each
|
||||
// FrequencyList_v2 model to determine working frequencies for each
|
||||
// band. The row index of this model is returned by this classes
|
||||
// hopping scheduling method so it may be conveniently used to select
|
||||
// a new working frequency by a client.
|
||||
|
@ -1,153 +0,0 @@
|
||||
get_target_property (QtCore_location Qt5::Core LOCATION)
|
||||
get_filename_component (QtCore_location ${QtCore_location} PATH)
|
||||
list (APPEND fixup_library_dirs ${QtCore_location})
|
||||
|
||||
if (APPLE OR WIN32)
|
||||
# install rules for including 3rd party libs such as Qt
|
||||
|
||||
# install a qt.conf file
|
||||
install (CODE "
|
||||
get_filename_component (the_qt_conf \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" REALPATH)
|
||||
file (WRITE \"\${the_qt_conf}\"
|
||||
\"[Paths]
|
||||
\")
|
||||
"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
# if a system Qt is used (e.g. installed in /usr/lib/), it will not be included in the installation
|
||||
set (fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/${CMAKE_PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
|
||||
#get_filename_component (hamlib_lib_dir ${Hamlib_LIBRARIES} PATH)
|
||||
|
||||
if (APPLE)
|
||||
# install required Qt plugins
|
||||
install (
|
||||
DIRECTORY
|
||||
${QT_PLUGINS_DIR}/platforms
|
||||
${QT_PLUGINS_DIR}/audio
|
||||
${QT_PLUGINS_DIR}/accessible
|
||||
${QT_PLUGINS_DIR}/imageformats
|
||||
${QT_PLUGINS_DIR}/styles
|
||||
DESTINATION ${WSJT_PLUGIN_DESTINATION}
|
||||
CONFIGURATIONS Release MinSizeRel RelWithDebInfo
|
||||
#COMPONENT runtime
|
||||
FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*webgl*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*_debug${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}.dSYM" EXCLUDE
|
||||
)
|
||||
install (
|
||||
FILES
|
||||
${QT_PLUGINS_DIR}/sqldrivers/libqsqlite${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
DESTINATION ${WSJT_PLUGIN_DESTINATION}/sqldrivers
|
||||
CONFIGURATIONS Release MinSizeRel RelWithDebInfo
|
||||
#COMPONENT runtime
|
||||
)
|
||||
# install (
|
||||
# DIRECTORY
|
||||
# ${QT_PLUGINS_DIR}/platforms
|
||||
# ${QT_PLUGINS_DIR}/audio
|
||||
# ${QT_PLUGINS_DIR}/accessible
|
||||
# DESTINATION ${WSJT_PLUGIN_DESTINATION}
|
||||
# CONFIGURATIONS Debug
|
||||
# #COMPONENT runtime
|
||||
# FILES_MATCHING PATTERN "*_debug${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
# PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# )
|
||||
|
||||
# add plugins path for Mac Bundle
|
||||
install (CODE "
|
||||
get_filename_component (the_qt_conf \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" REALPATH)
|
||||
file (APPEND \"\${the_qt_conf}\"
|
||||
\"Plugins = PlugIns
|
||||
\")
|
||||
"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
endif (APPLE)
|
||||
|
||||
if (WIN32)
|
||||
# DLL directories
|
||||
get_filename_component (hamlib_lib_dir ${Hamlib_LIBRARY} PATH)
|
||||
list (APPEND fixup_library_dirs ${hamlib_lib_dir}/../bin)
|
||||
|
||||
get_filename_component (usb_lib_dir ${Usb_LIBRARY} PATH)
|
||||
list (APPEND fixup_library_dirs ${usb_lib_dir})
|
||||
|
||||
get_filename_component (portaudio_lib_dir ${Portaudio_LIBRARY} PATH)
|
||||
list (APPEND fixup_library_dirs ${portaudio_lib_dir}/../bin)
|
||||
|
||||
get_filename_component (fftw_lib_dir ${FFTW3F_LIBRARY} PATH)
|
||||
list (APPEND fixup_library_dirs ${fftw_lib_dir})
|
||||
|
||||
# install required Qt plugins
|
||||
install (
|
||||
DIRECTORY
|
||||
${QT_PLUGINS_DIR}/platforms
|
||||
${QT_PLUGINS_DIR}/styles
|
||||
${QT_PLUGINS_DIR}/accessible
|
||||
${QT_PLUGINS_DIR}/audio
|
||||
${QT_PLUGINS_DIR}/imageformats
|
||||
DESTINATION ${WSJT_PLUGIN_DESTINATION}
|
||||
CONFIGURATIONS Release MinSizeRel RelWithDebInfo
|
||||
#COMPONENT runtime
|
||||
FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
PATTERN "*d${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
)
|
||||
install (
|
||||
FILES
|
||||
${QT_PLUGINS_DIR}/sqldrivers/qsqlite${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
DESTINATION ${WSJT_PLUGIN_DESTINATION}/sqldrivers
|
||||
CONFIGURATIONS Release MinSizeRel RelWithDebInfo
|
||||
#COMPONENT runtime
|
||||
)
|
||||
# install (
|
||||
# DIRECTORY
|
||||
# ${QT_PLUGINS_DIR}/platforms
|
||||
# ${QT_PLUGINS_DIR}/accessible
|
||||
# ${QT_PLUGINS_DIR}/audio
|
||||
# DESTINATION ${WSJT_PLUGIN_DESTINATION}
|
||||
# CONFIGURATIONS Debug
|
||||
# #COMPONENT runtime
|
||||
# FILES_MATCHING PATTERN "*d${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
# PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
|
||||
# )
|
||||
|
||||
# add paths for WIN32
|
||||
file (RELATIVE_PATH _plugins_path "${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}" "${CMAKE_INSTALL_PREFIX}/${WSJT_PLUGIN_DESTINATION}")
|
||||
install (CODE "
|
||||
get_filename_component (the_qt_conf \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" REALPATH)
|
||||
file (APPEND \"\${the_qt_conf}\"
|
||||
\"Plugins = ${_plugins_path}
|
||||
\")
|
||||
"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
set (gp_tool "objdump") # we want MinGW tool - not MSVC (See GetPrerequisites.cmake)
|
||||
endif (WIN32)
|
||||
|
||||
INSTALL (CODE "
|
||||
get_filename_component (the_path \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_PLUGIN_DESTINATION}\" REALPATH)
|
||||
file (GLOB_RECURSE QTPLUGINS \"\${the_path}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\")
|
||||
include (BundleUtilities)
|
||||
set (BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
set (gp_tool ${gp_tool})
|
||||
# canonicalize path in install context
|
||||
get_filename_component (the_exe ${fixup_exe} REALPATH)
|
||||
fixup_bundle (\"\${the_exe}\" \"\${QTPLUGINS}\" \"${fixup_library_dirs}\")"
|
||||
#COMPONENT runtime
|
||||
)
|
||||
endif (APPLE OR WIN32)
|
||||
|
@ -26,9 +26,10 @@ typedef struct dec_data {
|
||||
int nutc; //UTC as integer, HHMM
|
||||
bool ndiskdat; //true ==> data read from *.wav file
|
||||
int ntrperiod; //TR period (seconds)
|
||||
int nQSOProgress; //QSO state machine state
|
||||
int nQSOProgress; /* QSO state machine state */
|
||||
int nfqso; //User-selected QSO freq (kHz)
|
||||
int nftx; //TX audio offset where replies might be expected
|
||||
int nftx; /* Transmit audio offset where
|
||||
replies might be expected */
|
||||
bool newdat; //true ==> new data, must do long FFT
|
||||
int npts8; //npts for c0() array
|
||||
int nfa; //Low decode limit (Hz)
|
||||
@ -58,7 +59,6 @@ typedef struct dec_data {
|
||||
int naggressive;
|
||||
bool nrobust;
|
||||
int nexp_decode;
|
||||
int max_drift;
|
||||
char datetime[20];
|
||||
char mycall[12];
|
||||
char mygrid[6];
|
||||
|
@ -1,33 +1,34 @@
|
||||
Here are the "displayWidgets()" strings for WSJT-X modes
|
||||
|
||||
1 2 3
|
||||
01234567890123456789012345678901234567
|
||||
-------------------------------------------------
|
||||
JT4 11101000000011000011000000000000000000
|
||||
JT4/VHF 11111001001011011011110000000000000000
|
||||
JT9 11101000000011100001000000000000100000
|
||||
JT9/VHF 11111010100011111001000000000000000000
|
||||
JT65 11101000000011100001000000000000100000
|
||||
JT65/VHF 11111001000011011010110001000000000000
|
||||
Q65 11111101011011010011100000010000000011
|
||||
ISCAT 10011100000000011000000000000000000000
|
||||
MSK144 10111111010000000001000100000000000000
|
||||
WSPR 00000000000000000101000000000000000000
|
||||
FST4 11111100010011100001000000010000001100
|
||||
FST4W 00000000000000000101000000000000010000
|
||||
Echo 00000000000000000000001000000000000000
|
||||
FCal 00110100000000000000000000000100000000
|
||||
FT8 11101000010011100001000010011000100000
|
||||
FT8/VHF 11101000010011100001000010011000100000
|
||||
FT8/Fox 11101000010011100001000000000010000000
|
||||
FT8/Hound 11101000010011100001000000000011000000
|
||||
-------------------------------------------------
|
||||
0123456789012345678901234567890123456
|
||||
------------------------------------------------
|
||||
JT4 1110100000001100001100000000000000000
|
||||
JT4/VHF 1111100100101101101111000000000000000
|
||||
JT9 1110100000001110000100000000000010000
|
||||
JT9/VHF 1111101010001111100100000000000000000
|
||||
JT9+JT65 1110100000011110000100000000000010000
|
||||
JT65 1110100000001110000100000000000010000
|
||||
JT65/VHF 1111100100001101101011000100000000000
|
||||
Q65 1111110101101101001110000001000000001
|
||||
ISCAT 1001110000000001100000000000000000000
|
||||
MSK144 1011111101000000000100010000000000000
|
||||
WSPR 0000000000000000010100000000000000000
|
||||
FST4 1111110001001110000100000001000000110
|
||||
FST4W 0000000000000000010100000000000001000
|
||||
Echo 0000000000000000000000100000000000000
|
||||
FCal 0011010000000000000000000000010000000
|
||||
FT8 1110100001001110000100001001100010000
|
||||
FT8/VHF 1110100001001110000100001001100010000
|
||||
FT8/Fox 1110100001001110000100000000001000000
|
||||
FT8/Hound 1110100001001110000100000000001100000
|
||||
----------------------------------------------
|
||||
1 2 3
|
||||
01234567890123456789012345678901234567
|
||||
012345678901234567890123456789012
|
||||
|
||||
-------------------------------------------------
|
||||
----------------------------------------------
|
||||
Mapping of column numbers to widgets
|
||||
-------------------------------------------------
|
||||
----------------------------------------------
|
||||
0. txFirstCheckbox
|
||||
1. TxFreqSpinBox
|
||||
2. RxFreqSpinBox
|
||||
@ -65,4 +66,3 @@ Mapping of column numbers to widgets
|
||||
34. sbF_Low
|
||||
35. sbF_High
|
||||
36. AutoClrAvg
|
||||
37. sbMaxDrift
|
||||
|
@ -49,11 +49,12 @@ set (UG_SRCS
|
||||
system-requirements.adoc
|
||||
transceiver-setup.adoc
|
||||
tutorial-example1.adoc
|
||||
tutorial-example2.adoc
|
||||
tutorial-example3.adoc
|
||||
tutorial-example4.adoc
|
||||
tutorial-example5.adoc
|
||||
tutorial-example6.adoc
|
||||
tutorial-download-samples.adoc
|
||||
tutorial-main-window.adoc
|
||||
tutorial-wide-graph-settings.adoc
|
||||
utilities.adoc
|
||||
vhf-features.adoc
|
||||
@ -62,9 +63,7 @@ set (UG_SRCS
|
||||
)
|
||||
|
||||
set (UG_IMGS
|
||||
images/active_stations.png
|
||||
images/Add_Frequency.png
|
||||
images/Add_station_info.png
|
||||
images/130610_2343-wav-80.png
|
||||
images/AstroData_2.png
|
||||
images/Astronomical_data.png
|
||||
images/auto-seq.png
|
||||
@ -73,8 +72,9 @@ set (UG_IMGS
|
||||
images/colors.png
|
||||
images/config-menu.png
|
||||
images/decode-menu.png
|
||||
images/decodes.png
|
||||
images/download_samples.png
|
||||
images/Echo_1296.png
|
||||
images/echo_144.png
|
||||
images/EME_Deep_0.png
|
||||
images/EME_Deep_1.png
|
||||
images/EME_Deep_2.png
|
||||
@ -95,7 +95,7 @@ set (UG_IMGS
|
||||
images/JT65B.png
|
||||
images/keyboard-shortcuts.png
|
||||
images/MSK144.png
|
||||
images/Q65_6m_ionoscatter.png
|
||||
images/QRA64.png
|
||||
images/WSPR_WideGraphControls.png
|
||||
images/WSPR_1a.png
|
||||
images/WSPR_2.png
|
||||
@ -224,7 +224,7 @@ foreach (lang ${LANGUAGES})
|
||||
SOURCE user_guide/wsjtx-main.adoc
|
||||
LANG "${lang}"
|
||||
OUTPUT html
|
||||
ASCIIDOCTOR_OPTIONS -d book -a data-uri -a toc=left
|
||||
ASCIIDOCTOR_OPTIONS -d book -a data-uri -a toc=left -a max-width=1024px
|
||||
DEPENDS ${common_SRCS} ${_sources}
|
||||
)
|
||||
document(
|
||||
|
@ -18,13 +18,12 @@ Here is an overview list, details are filled out below:
|
||||
* MSYS2 *nix like command line environment
|
||||
* Hamlib rig control library
|
||||
* Pkg Config Lite
|
||||
* Boost C++ libraries (see separate document)
|
||||
* portaudio library (used by map65)
|
||||
* Boost C++ libraries
|
||||
|
||||
Qt Framework
|
||||
------------
|
||||
|
||||
At the time of writing I recommend using Qt v5.15.2 64-bit, v5.15.1
|
||||
At the time of writing I recommend using Qt v5.15.0 64-bit, v5.15.1
|
||||
has a defect that affects us so is best avoided. You need the MinGW
|
||||
version as we do not support the MSVC version due to lack of a
|
||||
suitable FOSS Fortran complier. To install the Qt developer SDK you
|
||||
@ -32,7 +31,7 @@ should download the official Qt on-line installer, this allows you to
|
||||
install one or more variants of the Qt SDK and also to maintain and
|
||||
update the installation at a later date. There are many versions and
|
||||
components within versions available, you only need the base 64-bit
|
||||
MinGW framework for Qt v5.15.2 and the matching MinGW 8.1.0 64-bit
|
||||
MinGW framework for Qt v5.15.0 and the matching MinGW 8.1.0 64-bit
|
||||
developer tools, other components can be unchecked within the on-line
|
||||
installer. The default install location is C:\Qt which is fine, do
|
||||
not attempt to move the location of the installed libraries if you
|
||||
@ -81,15 +80,19 @@ installed and updated you will need to install some packages, these
|
||||
are needed to provide the necessary *nix tools and utilities to build
|
||||
Hamlib from sources.
|
||||
|
||||
pacman -S autoconf automake libtool make tar
|
||||
pacman -S autoconf automake libtool make
|
||||
|
||||
Hamlib
|
||||
------
|
||||
|
||||
There is a fork of the official Hamlib project which we keep up to
|
||||
date with the official project master branch, we recommend building
|
||||
from the 'integration' branch, or a suitable tag on that fork. The
|
||||
fork is a git repository which can be cloned with this command:
|
||||
Currently we statically link Hamlib to avoid clashes with
|
||||
pre-installed DLLs that may be older versions than we support. Once
|
||||
Hamlib v1.4 is officially released and commonly available we will move
|
||||
to dynamic linking. Until then Hamlib must be built from
|
||||
sources. There is a fork of the official Hamlib project which we keep
|
||||
up to date with the official project master branch, we recommend
|
||||
building from the 'integration' branch of that fork. The fork is a git
|
||||
repository which can be cloned with this command:
|
||||
|
||||
mkdir -p ~/src/sf/bsomervi
|
||||
cd !$
|
||||
@ -99,13 +102,13 @@ fork is a git repository which can be cloned with this command:
|
||||
|
||||
Next you must build Hamlib using the MinGW compiler tools bundled with
|
||||
Qt. As you will build Hamlib again when there are updates you should
|
||||
set up you MSYS2 command line environment for this. I use a
|
||||
set up you Msys2 command line environment for this. I use a
|
||||
$HOME/.bash_profile file containing these lines:
|
||||
|
||||
dll_paths_64bit=/c/Tools/libusb-1.0.23/MinGW64/dll:$HOME/local/hamlib/mingw64/release/bin
|
||||
dll_paths_64bit=/c/Tools/libusb-1.0.23/MinGW64/dll
|
||||
export PATH=/c/Qt/Tools/mingw810_64/bin:$dll_paths_64bit:$PATH
|
||||
|
||||
Test the amended ~/.bash_profile file by opening a new MSYS2 shell and
|
||||
Test the amended ~/.bash_profile file by opening a new Msys2 shell and
|
||||
typing:
|
||||
|
||||
which gcc
|
||||
@ -118,13 +121,13 @@ Hamlib sources:
|
||||
cd ~/src/sf/bsomervi/hamlib
|
||||
./bootstrap
|
||||
|
||||
Now you need to configure and build Hamlib from an MSYS2 shell. Create
|
||||
Now you need to configure and build Hamlib from an Msys2 shell. Create
|
||||
a build directory outside of the Hamlib sources you have just cloned,
|
||||
then change working directory to that build directory.
|
||||
|
||||
mkdir -p ~/build/hamlib/release
|
||||
cd !$
|
||||
~/src/sf/bsomervi/hamlib/configure --enable-shared --disable-static \
|
||||
~/src/sf/bsomervi/hamlib/configure --disable-shared \
|
||||
--prefix=$HOME/local/hamlib/mingw64/release \
|
||||
CFLAGS="-DNDEBUG -g -O2 -fdata-sections -ffunction-sections -I/c/Tools/libusb-1.0.23/include" \
|
||||
CXXFLAGS="-DNDEBUG -g -O2 -fdata-sections -ffunction-sections" \
|
||||
@ -141,7 +144,7 @@ for tracking down issues:
|
||||
|
||||
mkdir -p ~/build/hamlib/debug
|
||||
cd !$
|
||||
~/src/sf/bsomervi/hamlib/configure --enable-shared --disable-static \
|
||||
~/src/sf/bsomervi/hamlib/configure --disable-shared \
|
||||
--prefix=$HOME/local/hamlib/mingw64/debug \
|
||||
CFLAGS="-g -O0 -I/c/Tools/libusb-1.0.23/include" \
|
||||
CXXFLAGS="-g -O0" \
|
||||
@ -157,12 +160,6 @@ To update the Hamlib sources to the latest commit and rebuild:
|
||||
cd ~/build/hamlib/debug
|
||||
make && make install
|
||||
|
||||
Note that the WSJT-X CMake build script will not detect an updated
|
||||
build of the Hamlib DLL, so to avoid using an out-of-date Hamlib DLL
|
||||
you should delete the Hamlib DLL (libhamlib-4.dll) from your WSJT-X
|
||||
release configuration install tree before rebuilding and installing
|
||||
WSJT-X after a Hamlib update.
|
||||
|
||||
Pkg Config Lite
|
||||
---------------
|
||||
|
||||
@ -172,74 +169,3 @@ from https://sourceforge.net/projects/pkgconfiglite/files/0.28-1/ and
|
||||
unzip it into a convenient location, as with other ancillary tools and
|
||||
libraries I put these under C:\Tools\.
|
||||
|
||||
portaudio
|
||||
---------
|
||||
|
||||
This library is only available as sources so must be built. It uses
|
||||
autotools and building using MinGW tools from an MSYS2 shell is
|
||||
recommended. Ensure your MSYS2 shell environment (PATH) is correctly
|
||||
set up for the MinGW tool chain you wish to build with, i.e. the MinGW
|
||||
tools bundled with the Qt installation for 32-, or 64-bit as required.
|
||||
|
||||
Download this specific version's sources tarball from
|
||||
http://files.portaudio.com/download.html , at the time of writing that
|
||||
was the pa_stable_v190600_20161030.tgz file. Unzip and unpack the
|
||||
tarball in a suitable location like ~/src :
|
||||
|
||||
cd ~/src
|
||||
tar xf ~/Downloads/pa_stable_v190600_20161030.tgz
|
||||
|
||||
|
||||
Note that on Windows portaudio will only build static libraries using
|
||||
the standard configuration, we prefer dynamic libraries for portaudio
|
||||
as users may wish to substitute a build of the library with ASIO
|
||||
support for personal use (we cannot redistribute binaries built from
|
||||
proprietary closed source sources like the Steinberg ASIO SDK).
|
||||
|
||||
In order to build DLLs on Windows the configure script requires a
|
||||
patch as follows:
|
||||
|
||||
sed -i -e 's/-luuid//g' ~/src/portaudio/configure
|
||||
|
||||
This removes linker dependencies on the MS uuid library since it is
|
||||
only available as a static archive and using that would disallow
|
||||
shared library creation.
|
||||
|
||||
Out-of-source-tree builds are recommended, create a build directory in
|
||||
a suitable location like ~/build and change working directory to it:
|
||||
|
||||
mkdir -p ~/build/portaudio/mingw64
|
||||
cd !$
|
||||
|
||||
Configure and build and install the library in a suitable place (I use
|
||||
~/local as a root directory for installed packages.
|
||||
|
||||
~/src/portaudio/configure --prefix=$HOME/local/portaudio/mingw64 \
|
||||
--with-winapi=wmme,directx,wdmks --disable-static --enable-shared CFLAGS=-DNDEBUG
|
||||
make && make install
|
||||
|
||||
Repeat for the 32-bit architecture if required, using a suitable MSYS2
|
||||
environment for the required tool chain, different build directory,
|
||||
and install location.
|
||||
|
||||
Update your CMake tool chain files to include the install directory,
|
||||
or directories, above. I have something like this in the 64-bit tool
|
||||
chain files:
|
||||
|
||||
# ...
|
||||
set (PORTAUDIODIR C:/Users/bill/local/portaudio/mingw64)
|
||||
# ...
|
||||
set (CMAKE_PREFIX_PATH ... ${PORTAUDIODIR} ...)
|
||||
#...
|
||||
|
||||
and similarly with the 32-bit tool chain file specifying the mingw32
|
||||
portaudio installation root directory.
|
||||
|
||||
To run Debug configuration WSJT-X builds you will also need to add the
|
||||
location of the portaudio DLL to your PATH environment variable, like:
|
||||
|
||||
SET "Path=%UserProfile%\local\portaudio\mingw64\bin;%Path%"
|
||||
|
||||
Verify the setup with:
|
||||
|
||||
WHERE libportaudio-2.dll
|
||||
|
@ -1,77 +0,0 @@
|
||||
Building the MS Windows portaudio DLL with ASIO Support
|
||||
=======================================================
|
||||
|
||||
Some MAP65 users may not be able to use WDM/KS hosted audio devices
|
||||
due to sharing issues with other applications, to circumvent this they
|
||||
can build a version of the portaudio DLL with ASIO support. We cannot
|
||||
provide a portaudio DLL with ASIO support as the Steinberg ASIO SDK
|
||||
license prevents redistribution of drivers or hosting applications
|
||||
without a commercial license agreement, nor is the Steinberg ASIO SDK
|
||||
license compatible with the GPL v3 license that MAP65 is released
|
||||
under. Users may build a portaudio DLL themselves, strictly for
|
||||
personal use, under the terms of the Steinberg ASIO license.
|
||||
|
||||
Building portaudio on MS Windows is done most easily using the MinGW
|
||||
(GNU) tool-chain which can be installed on MS Windows using the MSYS2
|
||||
unix like environment which in turn includes a package manager
|
||||
(pacman) that allows simple installation of necessary prerequisite
|
||||
packages like the MinGW 64-bit tool-chain. To install MSYS2 download
|
||||
the latest 64-bit installer from the MSYS2 project web site. This page
|
||||
contains links to the installer download and detailed instructions to
|
||||
install and bring up-to-date the base MSYS2 packages.
|
||||
|
||||
https://www.msys2.org/wiki/MSYS2-installation/
|
||||
|
||||
Take particular care to restart the MSYS2 shell window when directed
|
||||
to.
|
||||
|
||||
The first step is to install some prerequisite packages which contain
|
||||
the tools needed to prepare and build the portaudio DLL. Execute the
|
||||
following command to do that:
|
||||
|
||||
pacman -S make diffutils unzip mingw-w64-x86_64-gcc sed tar curl
|
||||
|
||||
Once MSYS2 is installed and the prerequisite packages above are
|
||||
installed you will find a new Windows Start Menu entry labelled "MSYS2
|
||||
MinGW 64-bit", use that to start a fresh MSYS2 shell window for the
|
||||
rest of these instructions.
|
||||
|
||||
Then make directories to put downloaded sources in and for building:
|
||||
|
||||
mkdir -p ~/src ~/build/portaudio
|
||||
|
||||
Fetch and unpack the Steinberg ASIO SDK (note the ASIO SDK license
|
||||
document included, particularly that it strictly disallows
|
||||
redistribution of the DLL we will be building here), and portaudio
|
||||
sources:
|
||||
|
||||
curl -Lo ~/src/asiosdk.zip https://www.steinberg.net/asiosdk
|
||||
(cd ~/src ; unzip asiosdk.zip)
|
||||
curl -O --output-dir ~/src \
|
||||
http://files.portaudio.com/archives/pa_stable_v190700_20210406.tgz
|
||||
tar -C ~/src -xf ~/src/pa_stable_v190700_20210406.tgz
|
||||
|
||||
Patch and build the portaudio library:
|
||||
|
||||
sed -i -e 's/-luuid//g' ~/src/portaudio/configure
|
||||
cd ~/build/portaudio
|
||||
~/src/portaudio/configure --with-winapi=wmme,directx,wdmks,asio \
|
||||
--with-asiodir=$HOME/src/asiosdk_2.3.3_2019-06-14 \
|
||||
--disable-static --enable-shared
|
||||
make -j
|
||||
|
||||
You can check the library build is working by running a test program
|
||||
that was also built:
|
||||
|
||||
bin/pa_devs
|
||||
|
||||
which should list every audio device on your system by every host API,
|
||||
if all is well that should include the audio devices on your system
|
||||
with ASIO drivers.
|
||||
|
||||
Copy the new portaudio DLL to your WSJT-X/MAP65 installation directory:
|
||||
|
||||
cp lib/.libs/libportaudio-2.dll /c/WSJT/wsjtx/bin/
|
||||
|
||||
Note that if you upgrade WSJT-X you will need to copy this DLL again
|
||||
since it will be overwritten by one with no ASIO support.
|
@ -141,7 +141,7 @@ C:\Tools\boost-build\MinGW32\bin\b2 -j8 toolset=gcc ^
|
||||
--build-dir=%USERPROFILE%\build\boost ^
|
||||
address-model=32 architecture=x86 variant=debug,release ^
|
||||
link=shared threading=multi ^
|
||||
--with-log --with-stacktrace --with-timer --prefix=C:\Tools\boost install
|
||||
--with-log --with-stacktrace --prefix=C:\Tools\boost install
|
||||
|
||||
If all is well you should see the following line about a 1/3 of the
|
||||
way through the initial configuration steps.
|
||||
@ -188,7 +188,7 @@ cd ..\..
|
||||
C:\Tools\boost-build\MinGW64\bin\b2 -j8 toolset=gcc-8~64 ^
|
||||
address-model=64 architecture=x86 variant=debug,release ^
|
||||
link=shared threading=multi ^
|
||||
--with-log --with-stacktrace --with-timer ^
|
||||
--with-log --with-stacktrace ^
|
||||
--build-dir=%USERPROFILE%\build\boost ^
|
||||
--prefix=C:\Tools\boost install
|
||||
|
||||
@ -206,11 +206,9 @@ After some time it should complete with something like:
|
||||
warnings can usually be ignored. If successful; you can release some
|
||||
space by cleaning the build tree:
|
||||
|
||||
C:\Tools\boost-build\MinGW64\bin\b2 toolset=gcc-8~64 ^
|
||||
C:\Tools\boost-build\MinGW32\bin\b2 toolset=gcc-8~64 ^
|
||||
address-model=64 --build-dir=%USERPROFILE%\build\boost ^
|
||||
--build-type=complete clean
|
||||
|
||||
|
||||
Run-time Environment
|
||||
--------------------
|
||||
|
||||
|
@ -49,44 +49,44 @@ d). Edit lines as needed. Keeping them in alphabetic order help see dupes.
|
||||
:asciidoctor_style: https://asciidoctor.org/docs/asciidoc-writers-guide/#delimited-blocks[AsciiDoctor Styles Guide]
|
||||
:asciidoctor_syntax: https://asciidoctor.org/docs/asciidoc-writers-guide/#delimited-blocks[AsciiDoctor Syntax Guide]
|
||||
:cc_by_sa: https://creativecommons.org/licenses/by-sa/3.0/[Commons Attribution-ShareAlike 3.0 Unported License]
|
||||
:debian32: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx_{VERSION}_i386.deb[wsjtx_{VERSION}_i386.deb]
|
||||
:debian64: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx_{VERSION}_amd64.deb[wsjtx_{VERSION}_amd64.deb]
|
||||
:raspbian: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx_{VERSION}_armhf.deb[wsjtx_{VERSION}_armhf.deb]
|
||||
:raspbian64: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx_{VERSION}_arm64.deb[wsjtx_{VERSION}_arm64.deb]
|
||||
:debian32: https://physics.princeton.edu/pulsar/K1JT/wsjtx_{VERSION}_i386.deb[wsjtx_{VERSION}_i386.deb]
|
||||
:debian64: https://physics.princeton.edu/pulsar/K1JT/wsjtx_{VERSION}_amd64.deb[wsjtx_{VERSION}_amd64.deb]
|
||||
:raspbian: https://physics.princeton.edu/pulsar/K1JT/wsjtx_{VERSION}_armhf.deb[wsjtx_{VERSION}_armhf.deb]
|
||||
:raspbian64: https://physics.princeton.edu/pulsar/K1JT/wsjtx_{VERSION}_arm64.deb[wsjtx_{VERSION}_arm64.deb]
|
||||
:debian: https://www.debian.org/[Debian]
|
||||
:dev_guide: https://wsjt.sourceforge.io/wsjtx-doc/wsjt-dev-guide.html[Dev-Guide]
|
||||
:dev_guide: https://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/wsjt-dev-guide.html[Dev-Guide]
|
||||
:devsvn: https://sourceforge.net/p/wsjt/wsjt/HEAD/tree/[Devel-SVN]
|
||||
:devrepo: https://sourceforge.net/p/wsjt/wsjtx/ci/master/tree/[SourceForge]
|
||||
:dimension4: http://www.thinkman.com/dimension4/[Thinking Man Software]
|
||||
:download: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx.html[Download Page]
|
||||
:download: https://physics.princeton.edu/pulsar/K1JT/wsjtx.html[Download Page]
|
||||
:dxatlas: http://www.dxatlas.com/[Afreet Software, Inc.]
|
||||
:dxlcommander: https://www.dxlabsuite.com/commander/[Commander]
|
||||
:dxlsuite: https://www.dxlabsuite.com/[DX Lab Suite]
|
||||
:fedora32: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx-{VERSION}-i686.rpm[wsjtx-{VERSION}-i686.rpm]
|
||||
:fedora64: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx-{VERSION}-x86_64.rpm[wsjtx-{VERSION}-x86_64.rpm]
|
||||
:fedora32: https://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-i686.rpm[wsjtx-{VERSION}-i686.rpm]
|
||||
:fedora64: https://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-x86_64.rpm[wsjtx-{VERSION}-x86_64.rpm]
|
||||
:fmt_arrl: https://www.arrl.org/frequency-measuring-test[ARRL FMT Info]
|
||||
:fmt_group: https://groups.yahoo.com/neo/groups/FMT-nuts/info[FMT Group]
|
||||
:fmt_k5cm: http://www.k5cm.com/[FMT Event Info]
|
||||
:fmt_wspr: https://wsjt.sourceforge.io/FMT_User.pdf[Accurate Frequency Measurements with your WSPR Setup]
|
||||
:ft4_protocol: https://wsjt.sourceforge.io/FT4_Protocol.pdf[The FT4 Protocol for Digital Contesting]
|
||||
:ft4_ft8_protocols: https://wsjt.sourceforge.io/FT4_FT8_QEX.pdf[The FT4 and FT8 Communication Protocols]
|
||||
:fmt_wspr: https://www.physics.princeton.edu/pulsar/K1JT/FMT_User.pdf[Accurate Frequency Measurements with your WSPR Setup]
|
||||
:ft4_protocol: https://physics.princeton.edu/pulsar/k1jt/FT4_Protocol.pdf[The FT4 Protocol for Digital Contesting]
|
||||
:ft4_ft8_protocols: https://physics.princeton.edu/pulsar/k1jt/FT4_FT8_QEX.pdf[The FT4 and FT8 Communication Protocols]
|
||||
:ft8_tips: https://www.g4ifb.com/FT8_Hinson_tips_for_HF_DXers.pdf[FT8 Operating Guide]
|
||||
:ft8_DXped: https://wsjt.sourceforge.io/FT8_DXpedition_Mode.pdf[FT8 DXpedition Mode]
|
||||
:ft8_DXped: https://physics.princeton.edu/pulsar/k1jt/FT8_DXpedition_Mode.pdf[FT8 DXpedition Mode]
|
||||
:gnu_gpl: https://www.gnu.org/licenses/gpl-3.0.txt[GNU General Public License]
|
||||
:homepage: https://wsjt.sourceforge.io/index.html[WSJT Home Page]
|
||||
:homepage: https://physics.princeton.edu/pulsar/K1JT/[WSJT Home Page]
|
||||
:hrd: http://www.hrdsoftwarellc.com/[Ham Radio Deluxe]
|
||||
:jt4eme: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/WSJT-X_1.6.0_for_JT4_v7.pdf[Using WSJT-X for JT4 EME Operation]
|
||||
:jt65protocol: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/JT65.pdf[QEX]
|
||||
:jt4eme: https://physics.princeton.edu/pulsar/K1JT/WSJT-X_1.6.0_for_JT4_v7.pdf[Using WSJT-X for JT4 EME Operation]
|
||||
:jt65protocol: https://physics.princeton.edu/pulsar/K1JT/JT65.pdf[QEX]
|
||||
:jtalert: https://hamapps.com/[JTAlert]
|
||||
:launchpadki7mt: https://launchpad.net/~ki7mt[KI7MT PPA's]
|
||||
:log4om: https://www.log4om.com[Log4OM]
|
||||
:lunarEchoes: https://wsjt.sourceforge.io/LunarEchoes_QEX.pdf[QEX]
|
||||
:msk144: https://wsjt.sourceforge.io/MSK144_Protocol_QEX.pdf[QEX]
|
||||
:lunarEchoes: https://physics.princeton.edu/pulsar/K1JT/LunarEchoes_QEX.pdf[QEX]
|
||||
:msk144: https://physics.princeton.edu/pulsar/k1jt/MSK144_Protocol_QEX.pdf[QEX]
|
||||
:msvcpp_redist: https://www.microsoft.com/en-ph/download/details.aspx?id=40784[Microsoft VC++ 2013 Redistributable]
|
||||
:msys_url: https://sourceforge.net/projects/mingwbuilds/files/external-binary-packages/[MSYS Download]
|
||||
:n1mm_logger: https://n1mm.hamdocs.com/tiki-index.php[N1MM Logger+]
|
||||
:ntpsetup: https://www.satsignal.eu/ntp/setup.html[Network Time Protocol Setup]
|
||||
:osx_instructions: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/OSX_Readme[Mac OS X Install Instructions]
|
||||
:osx_instructions: https://physics.princeton.edu/pulsar/K1JT/OSX_Readme[Mac OS X Install Instructions]
|
||||
:ppa: https://en.wikipedia.org/wiki/Personal_Package_Archive[PPA]
|
||||
:projsummary: https://sourceforge.net/projects/wsjt/[Project Summary]
|
||||
:pskreporter: https://pskreporter.info/pskmap.html[PSK Reporter]
|
||||
@ -94,37 +94,35 @@ d). Edit lines as needed. Keeping them in alphabetic order help see dupes.
|
||||
:sourceforge-jtsdk: https://sourceforge.net/projects/jtsdk[SourceForge JTSDK]
|
||||
:ubuntu_sdk: https://launchpad.net/~ubuntu-sdk-team/+archive/ppa[Ubuntu SDK Notice]
|
||||
:win_openssl_packages: https://slproweb.com/products/Win32OpenSSL.html[Windows OpenSSL Packages]
|
||||
:win32_openssl: https://slproweb.com/download/Win32OpenSSL_Light-1_1_1s.msi[Win32 OpenSSL Light Package]
|
||||
:win64_openssl: https://slproweb.com/download/Win64OpenSSL_Light-1_1_1s.msi[Win64 OpenSSL Light Package]
|
||||
:win32_openssl: https://slproweb.com/download/Win32OpenSSL_Light-1_1_1j.msi[Win32 OpenSSL Light Package]
|
||||
:win64_openssl: https://slproweb.com/download/Win64OpenSSL_Light-1_1_1j.msi[Win64 OpenSSL Light Package]
|
||||
:writelog: https://writelog.com/[Writelog]
|
||||
:wsjtx_group: https://groups.io/g/wsjtgroup[WSJT GROUP User Forum]
|
||||
:wsjtx_group2: https://groups.io/g/wsjtgroup/join[join the group]
|
||||
:wsjtx: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx.html[WSJT-X]
|
||||
:wspr0_guide: https://wsjt.sourceforge.io/WSPR0_Instructions.TXT[WSPR0 Guide]
|
||||
:wspr: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wspr.html[WSPR Home Page]
|
||||
:wsjtx_group: https://groups.io/g/WSJTX[WSJTX Group]
|
||||
:wsjtx: https://physics.princeton.edu/pulsar/K1JT/wsjtx.html[WSJT-X]
|
||||
:wspr0_guide: https://www.physics.princeton.edu/pulsar/K1JT/WSPR0_Instructions.TXT[WSPR0 Guide]
|
||||
:wspr: https://physics.princeton.edu/pulsar/K1JT/wspr.html[WSPR Home Page]
|
||||
:wsprnet: https://wsprnet.org/drupal/[WSPRnet]
|
||||
:wsprnet_activity: https://wsprnet.org/drupal/wsprnet/activity[WSPRnet Activity page]
|
||||
|
||||
// Download Links
|
||||
:cty_dat: https://www.country-files.com/bigcty/cty.dat/[Amateur Radio Country Files]
|
||||
:cty_dat: https://www.country-files.com/cty/[Amateur Radio Country Files]
|
||||
:jtbridge: https://jt-bridge.eller.nu/[JT-Bridge]
|
||||
:jtsdk_doc: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/JTSDK-DOC.exe[Download]
|
||||
:jtsdk_doc: https://physics.princeton.edu/pulsar/K1JT/JTSDK-DOC.exe[Download]
|
||||
:jtsdk_installer: https://sourceforge.net/projects/jtsdk/files/win32/2.0.0/JTSDK-2.0.0-B2-Win32.exe/download[Download]
|
||||
:jtsdk_omnirig: https://sourceforge.net/projects/jtsdk/files/win32/2.0.0/base/contrib/OmniRig.zip/download[Download]
|
||||
:jtsdk_py: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/JTSDK-PY.exe[Download]
|
||||
:jtsdk_qt: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/JTSDK-QT.exe[Download]
|
||||
:jtsdk_py: https://physics.princeton.edu/pulsar/K1JT/JTSDK-PY.exe[Download]
|
||||
:jtsdk_qt: https://physics.princeton.edu/pulsar/K1JT/JTSDK-QT.exe[Download]
|
||||
:jtsdk_vcredist: https://sourceforge.net/projects/jtsdk/files/win32/2.0.0/base/contrib/vcredist_x86.exe/download[Download]
|
||||
:nh6z: http://www.nh6z.net/Amatuer_Radio_Station_NH6Z/Other_Peoples_Software.html[here]
|
||||
:omnirig: http://www.dxatlas.com/OmniRig/Files/OmniRig.zip[Omni-Rig]
|
||||
:osx: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx-{VERSION}-Darwin.dmg[wsjtx-{VERSION}-Darwin.dmg]
|
||||
:QRA64_EME: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/QRA64_EME.pdf[QRA64 for microwave EME]
|
||||
:osx: https://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-Darwin.dmg[wsjtx-{VERSION}-Darwin.dmg]
|
||||
:QRA64_EME: https://physics.princeton.edu/pulsar/K1JT/QRA64_EME.pdf[QRA64 for microwave EME]
|
||||
:svn: https://subversion.apache.org/packages.html#windows[Subversion]
|
||||
:win32: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx-{VERSION}-win32.exe[wsjtx-{VERSION}-win32.exe]
|
||||
:win64: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/wsjtx-{VERSION}-win64.exe[wsjtx-{VERSION}-win64.exe]
|
||||
:wsjt-devel: https://sourceforge.net/projects/wsjt/lists/wsjt-devel/[join the group]
|
||||
:wsjt-devel2: https://sourceforge.net/projects/wsjt/lists/wsjt-devel/[subscribe to the list]
|
||||
:win32: https://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-win32.exe[wsjtx-{VERSION}-win32.exe]
|
||||
:win64: https://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-win64.exe[wsjtx-{VERSION}-win64.exe]
|
||||
:wsjt-devel: https://lists.sourceforge.net/lists/listinfo/wsjt-devel[here]
|
||||
:wsjt_repo: https://sourceforge.net/p/wsjt/wsjt_orig/ci/master/tree/[WSJT Source Repository]
|
||||
:wspr_code: https://sourceforge.net/projects/wsjt/files/wsjtx-{VERSION}/WSPRcode.exe[WSPRcode.exe]
|
||||
:wspr_code: https://physics.princeton.edu/pulsar/K1JT/WSPRcode.exe[WSPRcode.exe]
|
||||
:wspr_svn: https://sourceforge.net/p/wsjt/wspr/ci/master/tree/[WSPR Source Repository]
|
||||
|
||||
// MAIL-TO links
|
||||
@ -134,7 +132,7 @@ d). Edit lines as needed. Keeping them in alphabetic order help see dupes.
|
||||
:dev_mail_svn: https://sourceforge.net/auth/subscriptions/[WSJT SVN Archives]
|
||||
:devmail: mailto:wsjt-devel@lists.sourceforge.net[wsjt-devel@lists.sourceforge.net]
|
||||
:devmail1: mailto:wsjt-devel@lists.sourceforge.net[Post Message]
|
||||
:wsjtgroup_mail: mailto:wsjtgroup@groups.io[Post Message]
|
||||
:wsjtgroup_mail: mailto:WSJTX@groups.io[Post Message]
|
||||
:greg_beam: mailto:ki7mt@yahoo.com[KI7MT]
|
||||
:joe_taylor: mailto:joe@princeton.edu[K1JT]
|
||||
:stuart_rackman: mailto:srackham@gmail.com[Stuart Rackham]
|
||||
|
@ -1,24 +1,21 @@
|
||||
// Status=review
|
||||
|
||||
The _WSJT_ project was started by *K1JT* in 2001. Since 2005 it has
|
||||
been an Open Source project, and it has included the programs _WSJT_,
|
||||
_MAP65_, _WSPR_, _WSJT-X_, and _QMAP_. *G4WJS* (since 2013), *K9AN*
|
||||
(since 2015), *IV3NWV* (since 2016), *DG2YCB* (since 2021), and
|
||||
*N9ADG* (since 2022) have made major contributions to _WSJT-X_.
|
||||
Together with K1JT they now form the core development team. *G4WJS*
|
||||
and *W9MDB* have made major contributions to the _hamlib_ library, on
|
||||
which _WSJT-X_ depends for rig control.
|
||||
been an Open Source project, which now includes the programs _WSJT_,
|
||||
_MAP65_, _WSPR_, _WSJT-X_, and _WSPR-X_. *G4WJS* (since 2013) and
|
||||
*K9AN* (since 2015) have made major contributions to _WSJT-X_.
|
||||
Together with K1JT they now form the core development team.
|
||||
|
||||
All code in the _WSJT_ project is licensed under the GNU Public
|
||||
License (GPL). Many users of these programs, too numerous to mention
|
||||
here individually, have contributed suggestions and advice that have
|
||||
greatly aided the development of _WSJT_ and its sister programs. For
|
||||
_WSJT-X_ in particular, in addition to those mentioned above we
|
||||
acknowledge contributions from *AC6SL, AE4JY, DF2ET, DJ0OT, G3WDG,
|
||||
G4KLA, IW3RAB, K3WYC, KA1GT, KA6MAL, KA9Q, KB1ZMX, KD6EKQ, KI7MT,
|
||||
KK1D, ND0B, PY2SDR, VE1SKY, VK3ACF, VK4BDJ, VK7MO, W3DJS, W3SZ, W4TI,
|
||||
and W4TV*. Each of these amateurs has helped to bring the program’s
|
||||
design, code, testing, and/or documentation to its present state.
|
||||
_WSJT-X_ in particular, we acknowledge contributions from *AC6SL,
|
||||
AE4JY, DJ0OT, G3WDG, G4KLA, IV3NWV, IW3RAB, K3WYC, KA6MAL, KA9Q,
|
||||
KB1ZMX, KD6EKQ, KI7MT, KK1D, ND0B, PY2SDR, VE1SKY, VK3ACF, VK4BDJ,
|
||||
VK7MO, W4TI, W4TV, and W9MDB*. Each of these amateurs has helped to
|
||||
bring the program’s design, code, testing, and/or documentation to its
|
||||
present state.
|
||||
|
||||
Most of the color palettes for the _WSJT-X_ waterfall were copied from
|
||||
the excellent, well documented, open-source program _fldigi_, by *W1HKJ*
|
||||
|
@ -20,7 +20,6 @@ sky background temperature in the direction of the moon, scaled to the
|
||||
operating frequency; *Dpol*, the spatial polarization offset in
|
||||
degrees; *MNR*, the maximum non-reciprocity of the EME path in dB,
|
||||
owing to a combination of Faraday rotation and spatial polarization;
|
||||
*Dist*, the distance from your location to the moon, in km;
|
||||
and finally *Dgrd*, an estimate of the signal degradation in dB,
|
||||
relative to the best possible time with the moon at perigee in a cold
|
||||
part of the sky.
|
||||
|
@ -1,10 +1,8 @@
|
||||
// Status=edited
|
||||
|
||||
Controls related to frequency selection, received audio level, the
|
||||
station being called, and date and time are found in the lower,
|
||||
left-hand section of the main window. Buttons are provided for making
|
||||
quick changes among the modes FT8, FT4, MSK144, Q65, and JT65, and
|
||||
for toggling FT8 Hound mode ON or OFF.
|
||||
station being called, and date and time are found in the lower, left-hand section of the
|
||||
main window:
|
||||
|
||||
//.Misc Controls Left
|
||||
image::misc-main-ui.png[align="center",alt="Misc Menu Items"]
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Status=edited
|
||||
|
||||
The following controls appear just under the decoded text windows on
|
||||
the main screen. Some of them are visible only in certain modes.
|
||||
the main screen:
|
||||
|
||||
//.Main UI
|
||||
image::main-ui-controls.png[align="center",width=650,alt="Main UI Controls"]
|
||||
@ -11,9 +11,7 @@ image::main-ui-controls.png[align="center",width=650,alt="Main UI Controls"]
|
||||
* *Log QSO* raises a dialog window pre-filled with known information
|
||||
about a QSO you have nearly completed. You can edit or add to this
|
||||
information before clicking *OK* to log the QSO. If you check *Prompt
|
||||
me to log QSO* on the *File -> Settings -> Reporting* tab, the program
|
||||
raises the confirmation screen automatically when you send a message
|
||||
containing +73+. *Start Date* and *Start Time* are set when you click
|
||||
me to log QSO* on the *File -> Settings -> Reporting* tab, the program raises the confirmation screen automatically when you send a message containing +73+. *Start Date* and *Start Time* are set when you click
|
||||
to send the *Tx 2* or *Tx 3* message, and backed up by one or two
|
||||
sequence lengths, respectively. (Note that the actual start time may
|
||||
have been earlier if repeats of early transmissions were required.)
|
||||
|
@ -37,18 +37,7 @@ examples for configurations `FT8` and `Echo`:
|
||||
==== View Menu
|
||||
image::view-menu.png[align="left",alt="View Menu"]
|
||||
|
||||
*Active Stations* displays a window that can help you to work the most
|
||||
distant stations, in particular for the distance-scored ARRL
|
||||
International Digital Contest. Controls are provided to set the
|
||||
maximum length of the list and the maximum "`age`" of decodes in Rx
|
||||
sequences. You can request display of only ready-to-be-called
|
||||
stations. For the ARRL International Digital Contest the window
|
||||
displays scoring rate (points in the most recent hour), total score,
|
||||
and the number of band changes in the past hour.
|
||||
|
||||
image::active_stations.png[align="left",alt="Active Stations"]
|
||||
|
||||
*SWL Mode* reduces the _WSJT-X_ main window to a minimum
|
||||
The *SWL Mode* action reduces the _WSJT-X_ main window to a minimum
|
||||
size with just the menus, decodes windows, and status bar visible. You
|
||||
may find this useful when running multiple instances of the
|
||||
application. Both size and location of the main window are saved and
|
||||
|
@ -1,9 +1,10 @@
|
||||
// Status=edited
|
||||
|
||||
The following controls appear at the bottom of the Wide Graph window.
|
||||
Decoding occurs only in the displayed frequency range; otherwise,
|
||||
controls on the Wide Graph window have no effect on the decoding
|
||||
process.
|
||||
Decoding occurs only in the displayed frequency range; otherwise, with
|
||||
the exceptions of *Start NNN Hz* and of *JT65 nnnn JT9* when operating
|
||||
in JT9+JT65 mode, controls on the Wide Graph window have no effect on
|
||||
the decoding process.
|
||||
|
||||
image::wide-graph-controls.png[align="center",alt="Wide Graph Controls"]
|
||||
|
||||
@ -12,6 +13,11 @@ value to 1 for the highest possible resolution, or to higher numbers
|
||||
to compress the spectral display. Normal operation with a convenient
|
||||
window size works well at 2 to 8 bins per pixel.
|
||||
|
||||
- *JT65 nnnn JT9* sets the dividing point (blue marker) for wide-band
|
||||
decoding of JT65 and JT9 signals in *JT9+JT65* mode. The decoder
|
||||
looks for JT65 signals everywhere, but JT9 signals only above this
|
||||
frequency. This setting is stored separately for each band.
|
||||
|
||||
- *Start nnn Hz* sets the low-frequency starting point of the
|
||||
waterfall frequency scale.
|
||||
|
||||
|
@ -28,6 +28,8 @@ logging programs, audio and visual alerts following a number of
|
||||
optional alert conditions (decoding of a new DXCC, new state, etc.),
|
||||
and convenient direct access to web services such as callsign lookup.
|
||||
|
||||
image::jtalert.png[align="left",alt="JTAlert-X image"]
|
||||
|
||||
* {alarmejt}, by F5JMH, is available only for Linux. The program keeps
|
||||
its own logbook. It fetches contact information from _WSJT-X_ and
|
||||
provides visual alerts for new DXCC entities and grid squares on the
|
||||
|
@ -24,22 +24,20 @@ AP bits, with a specified level of confidence. Successful AP decodes
|
||||
are labeled with an end-of-line indicator of the form `aP`, where `P`
|
||||
is one of the single-digit AP decoding types listed in Table 1. For
|
||||
example, `a2` indicates that the successful decode used MyCall as
|
||||
hypothetically known information. Type `a7`, used only in FT8 mode,
|
||||
uses information from the previous Rx sequence.
|
||||
hypothetically known information.
|
||||
|
||||
[[FT8_AP_INFO_TABLE]]
|
||||
.FST4, FT4, and FT8 AP information types
|
||||
[width="35%",cols="1h,<10m",frame=topbot,options="header"]
|
||||
|===
|
||||
|aP|Message components
|
||||
|a1|CQ     ?     ?
|
||||
|a2|MyCall     ?     ?
|
||||
|a3|MyCall DxCall     ?
|
||||
|a4|MyCall DxCall RRR
|
||||
|a5|MyCall DxCall 73
|
||||
|a6|MyCall DxCall RR73
|
||||
|a7|(Call_1 or CQ) Call_2     ?
|
||||
|===
|
||||
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|
||||
|===============================================
|
||||
|aP | Message components
|
||||
|a1 | CQ     ?     ?
|
||||
|a2 | MyCall     ?     ?
|
||||
|a3 | MyCall DxCall     ?
|
||||
|a4 | MyCall DxCall RRR
|
||||
|a5 | MyCall DxCall 73
|
||||
|a6 | MyCall DxCall RR73
|
||||
|===============================================
|
||||
|
||||
If a codeword is found that is judged to have high (but not
|
||||
overwhelmingly high) probability of being correct, a `?` character is
|
||||
@ -55,8 +53,8 @@ is the same except that it omits the decoding attempts for AP types
|
||||
|
||||
[[FT8_AP_DECODING_TYPES_TABLE]]
|
||||
.FT4 and FT8 AP decoding types for each QSO state
|
||||
[width="35%",cols="10h,<20m",frame=topbot,options="header"]
|
||||
|===
|
||||
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|
||||
|===========================================
|
||||
|State |AP type
|
||||
|CALLING STN | 2, 3
|
||||
|REPORT | 2, 3
|
||||
@ -64,15 +62,15 @@ is the same except that it omits the decoding attempts for AP types
|
||||
|ROGERS | 3, 4, 5, 6
|
||||
|SIGNOFF | 3, 1, 2
|
||||
|CALLING CQ | 1, 2
|
||||
|===
|
||||
|===========================================
|
||||
|
||||
Decoding with _a priori_ information behaves slightly differently
|
||||
in JT65. Some details are provided in Tables 3 and 4.
|
||||
|
||||
[[JT65_AP_INFO_TABLE]]
|
||||
.JT65 AP information types
|
||||
[width="35%",cols="1h,<10m",frame=topbot,options="header"]
|
||||
|===
|
||||
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|
||||
|===============================================
|
||||
|aP | Message components
|
||||
|a1 | CQ     ?     ?
|
||||
|a2 | MyCall     ?     ?
|
||||
@ -81,20 +79,20 @@ in JT65. Some details are provided in Tables 3 and 4.
|
||||
|a5 | MyCall DxCall 73
|
||||
|a6 | MyCall DxCall DxGrid
|
||||
|a7 | CQ DxCall DxGrid
|
||||
|===
|
||||
|===============================================
|
||||
|
||||
[[JT65_AP_DECODING_TYPES_TABLE]]
|
||||
.JT65 AP decoding types for each QSO state
|
||||
[width="35%",cols="10h,<20m",frame=topbot,options="header"]
|
||||
|===
|
||||
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|
||||
|===========================================
|
||||
|State |AP type
|
||||
|CALLING STN |2, 3, 6, 7
|
||||
|REPORT |2, 3
|
||||
|ROGER_REPORT |3, 4, 5
|
||||
|ROGERS |3, 4, 5
|
||||
|SIGNOFF |2, 3, 4, 5
|
||||
|CALLING CQ |1, 2, 6
|
||||
|===
|
||||
|CALLING STN | 2, 3, 6, 7
|
||||
|REPORT | 2, 3
|
||||
|ROGER_REPORT | 3, 4, 5
|
||||
|ROGERS | 3, 4, 5
|
||||
|SIGNOFF | 2, 3, 4, 5
|
||||
|CALLING CQ | 1, 2, 6
|
||||
|===========================================
|
||||
|
||||
|
||||
=== Decoded Lines
|
||||
@ -111,10 +109,10 @@ summarized in the following Table:
|
||||
[[DECODED_LINES_TABLE]]
|
||||
.Notations used on decoded text lines
|
||||
[width="50%",cols="h,3*^",frame=topbot,options="header"]
|
||||
|===
|
||||
|===========================================
|
||||
|Mode |Mode character|Sync character|End of line information
|
||||
|FST4 | ` | | ?   aP
|
||||
|FT4 | + | | ?   aP
|
||||
|FT4 | ~ | | ?   aP
|
||||
|FT8 | ~ | | ?   aP
|
||||
|JT4 | $ | *, # | f, fN, dCN
|
||||
|JT9 | @ | |
|
||||
@ -122,7 +120,7 @@ summarized in the following Table:
|
||||
|JT65 VHF| # | *, # | f, fN, dCN
|
||||
|Q65 | : | | qP
|
||||
|MSK144 | & | |
|
||||
|===
|
||||
|===========================================
|
||||
Sync character::
|
||||
`*` - Normal sync +
|
||||
`#` - Alternate sync
|
||||
@ -138,13 +136,12 @@ End of line information::
|
||||
|
||||
[[Q65_AP_INFO_TABLE]]
|
||||
.Q65 end-of-line codes
|
||||
[width="50%",cols="1h,<10m",frame=topbot,options="header"]
|
||||
|===
|
||||
|qP|Message components
|
||||
|q0|?     ?     ?
|
||||
|q1|CQ     ?     ?
|
||||
|q2|MyCall     ?     ?
|
||||
|q3|MyCall DxCall     ?
|
||||
|q4|MyCall DxCall     [<blank> \| RRR \| RR73 \| 73]
|
||||
|q5|MyCall DxCall     ?         (*Max Drift* = 50)
|
||||
|===
|
||||
[width="45%",cols="h10,<m20",frame=topbot,options="header"]
|
||||
|===============================================
|
||||
| | Message components
|
||||
|q0 | ?     ?     ?
|
||||
|q1 | CQ     ?     ?
|
||||
|q2 | MyCall     ?     ?
|
||||
|q3 | MyCall DxCall     ?
|
||||
|q4 | MyCall DxCall     [<blank> \| RRR \| RR73 \| 73]
|
||||
|===============================================
|
||||
|
@ -74,6 +74,12 @@ _Omni-Rig_ apparently has a bug that appears when you click *Test
|
||||
CAT*. Forget using *Test CAT* and just click *OK*. _Omni-Rig_ then
|
||||
behaves normally.
|
||||
|
||||
I am using _WSJT-X_ with _Ham Radio Deluxe_. All seems well until I start HRD Logbook or DM780 running in parallel; then CAT control becomes unreliable.::
|
||||
|
||||
You may see delays up to 20 seconds or so in frequency changes or
|
||||
other radio commands, due to a bug in HRD. HRD folks are aware of the
|
||||
problem, and are working to resolve it.
|
||||
|
||||
I am running _WSJT-X_ under Ubuntu. The program starts, but the menu bar is missing from the top of the main window and the hot-keys don't work.::
|
||||
|
||||
Ubuntu's new "`Unity`" desktop puts the menu for the currently active
|
||||
|
BIN
doc/user_guide/en/images/130610_2343-wav-80.png
Normal file
After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 177 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 229 KiB |
BIN
doc/user_guide/en/images/QRA64.png
Normal file
After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
BIN
doc/user_guide/en/images/decodes.png
Normal file
After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 9.3 KiB |
BIN
doc/user_guide/en/images/echo_144.png
Normal file
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.5 KiB |