На вашем сервере server.js:
var express = require("express");
var app = express();
app.use(express.static(__dirname + '/public'));
Вы объявляете экспресс и приложение отдельно, создайте папку с именем «public» или по своему усмотрению, и все же вы можете получить доступ к этой папке. В шаблоне src вы поместили относительный путь из / public (или имя вашей папки в статические файлы). Остерегайтесь баров на маршрутах.
У меня недавно была эта проблема, и оказалось , это была ошибка в Visual Studio Express 2013 . Мне пришлось удалить исходный файл из проекта и повторно добавить его, чтобы устранить ошибку.
Попытки попробовать, если вы считаете, что это может быть ошибка в компиляторе / IDE:
inline
. Пример: -
main.cpp
#include "gum.h"
#include "foo.h"
int main()
{
gum();
foo f;
f.bar();
return 0;
}
foo.h (1)
#pragma once
struct foo {
void bar() const;
};
gum.h (1)
#pragma once
extern void gum();
foo.cpp (1)
#include "foo.h"
#include <iostream>
inline /* <- wrong! */ void foo::bar() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
gum.cpp (1)
#include "gum.h"
#include <iostream>
inline /* <- wrong! */ void gum()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Если вы укажете, что gum
(аналогично, foo::bar
) является inline
в своем определении, то компилятор будет встроен gum
(если он выберет) , посредством: -
gum
, и, следовательно, gum
, и вместо этого gum
встроенными копиями скомпилированного тела из gum
. В результате, если вы определяете gum
inline в исходном файле gum.cpp
, он компилируется в объектный файл gum.o
, в котором все вызовы gum
являются встроенными, и символ не определен под которым линкер может ссылаться на gum
. Когда вы связываете gum.o
в программу вместе с другим объектным файлом, например, main.o
, которые делают ссылки на внешний символ gum
, компоновщик не может разрешить эти ссылки. Таким образом, связь не работает:
Компиляция:
g++ -c main.cpp foo.cpp gum.cpp
Ссылка:
$ g++ -o prog main.o foo.o gum.o
main.o: In function `main':
main.cpp:(.text+0x18): undefined reference to `gum()'
main.cpp:(.text+0x24): undefined reference to `foo::bar() const'
collect2: error: ld returned 1 exit status
Вы можете определить gum
как inline
, если компилятор может видеть его определение в каждом исходном файле, в котором может быть вызвано gum
. Это означает, что его встроенное определение должно существовать в файле заголовка , который вы включаете в каждый исходный файл, который вы компилируете, в который может быть вызван gum
. Сделайте одно из двух:
Либо не включайте определения
Удалите спецификатор inline
из определения исходного файла:
foo.cpp (2)
#include "foo.h"
#include <iostream>
void foo::bar() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
gum.cpp (2)
#include "gum.h"
#include <iostream>
void gum()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Перестройте с этим:
$ g++ -c main.cpp foo.cpp gum.cpp
imk@imk-Inspiron-7559:~/develop/so/scrap1$ g++ -o prog main.o foo.o gum.o
imk@imk-Inspiron-7559:~/develop/so/scrap1$ ./prog
void gum()
void foo::bar() const
Успех.
Или правильно встроенный
Встроенные определения в заголовочных файлах:
foo.h (2)
#pragma once
#include <iostream>
struct foo {
void bar() const { // In-class definition is implicitly inline
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
// Alternatively...
#if 0
struct foo {
void bar() const;
};
inline void foo::bar() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
#endif
] gum.h (2)
#pragma once
#include <iostream>
inline void gum() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Теперь нам не нужны foo.cpp
или gum.cpp
:
$ g++ -c main.cpp
$ g++ -o prog main.o
$ ./prog
void gum()
void foo::bar() const
Большинство современных компоновщиков включают опцию подробного вывода, которая печатает в различной степени;
Для gcc и clang; вы обычно добавляете -v -Wl,--verbose
или -v -Wl,-v
в командную строку. Более подробную информацию можно найти здесь:
Для MSVC, /VERBOSE
(в частности, /VERBOSE:LIB
) добавляется в командную строку ссылки.
/VERBOSE
. неопределенная ссылка на WinMain@16
или аналогичную «необычную» main()
точку входа (особенно для visual-studio ).
Возможно, вы пропустили выбор правильного типа проекта с вашей фактической IDE. IDE может захотеть связать, например, Приложение Windows проецирует на такую функцию точки входа (как указано в отсутствующей ссылке выше) вместо обычно используемой int main(int argc, char** argv);
подписи.
Если ваша IDE поддерживает Простые консольные проекты , вы можете выбрать этот тип проекта вместо проекта Windows-приложения.
Здесь case1 и case2 более подробно рассматриваются из проблемы реального мира .
Пакет Visual Studio NuGet необходимо обновить для новой версии набора инструментов
У меня только что возникла проблема при попытке связать libpng с Visual Studio 2013. Проблема в том, что файл пакета имел только библиотеки для Visual Studio 2010 и 2012.
Правильное решение - надеяться, что разработчик выпустит обновленный пакет, а затем обновит его, но он сработал для меня, взломав дополнительный параметр для VS2013, указывая на файлы библиотеки VS2012.
Я отредактировал пакет (в папке packages
внутри каталога решения), найдя packagename\build\native\packagename.targets
и внутри этого файла, скопировав все секции v110
. Я изменил v110
на v120
в только для полей условий , так как очень тщательно оставлял пути к именам файлов как v110
. Это просто позволило Visual Studio 2013 связываться с библиотеками на 2012 год, и в этом случае это сработало.
UNICODE
определения Сборка Windows UNICODE строится с TCHAR
и т. Д., Определенным как wchar_t
и т. Д. Когда не выполняется сборка с UNICODE
, определенным как сборка с TCHAR
, определенным как char
и т. Д. Эти определения UNICODE
и _UNICODE
влияют на все типы строк «T
» ; LPTSTR
, LPCTSTR
и их лось.
Создание одной библиотеки с определенным UNICODE
и попытка связать ее в проекте, где UNICODE
не определено, приведет к ошибкам компоновщика, поскольку в определении TCHAR
будет несоответствие; char
против wchar_t
.
Ошибка обычно включает в себя функцию со значением производного типа char
или wchar_t
, к ним также может относиться std::basic_string<>
и т. Д. При просмотре уязвимой функции в коде часто встречается ссылка на TCHAR
или std::basic_string<TCHAR>
и т. Д. Это контрольный признак того, что код изначально предназначался как для UNICODE, так и для многобайтового символа ( или "узкая") сборка.
Чтобы исправить это, соберите все необходимые библиотеки и проекты с непротиворечивым определением UNICODE
(и _UNICODE
).
Это можно сделать с помощью:
#define UNICODE
#define _UNICODE
Или в настройках проекта;
Свойства проекта> Общие > Проект по умолчанию> Набор символов
Или в командной строке;
/DUNICODE /D_UNICODE
Альтернатива также применима, если UNICODE не предназначен для использования, убедитесь, что определения не установлены, и / или многосимвольная настройка используется в проектах и применяется последовательно.
Не забывайте также соблюдать согласованность между сборками «Release» и «Debug».
Оболочка вокруг GNU ld, которая не поддерживает сценарии компоновщика
Некоторые файлы .so фактически сценарии компоновщика GNU ld , например, Файл libtbb.so представляет собой текстовый файл ASCII с таким содержимым:
INPUT (libtbb.so.2)
Некоторые более сложные сборки могут не поддерживать это. Например, если вы включите -v в опции компилятора, вы увидите, что mainwin gcc wrapper mwdip отбрасывает командные файлы сценария компоновщика в подробный список выходных библиотек для ссылки. Простой способ обойти это замените файл ввода команды сценария компоновщика вместо этого копией файла (или символической ссылкой), например
cp libtbb.so.2 libtbb.so
Или вы можете заменить аргумент -l на полный путь .so, например вместо -ltbb
делай /home/foo/tbb-4.3/linux/lib/intel64/gcc4.4/libtbb.so.2
Стандартное поведение gcc - все символы видимы. Однако, когда единицы перевода построены с опцией -fvisibility=hidden
, только функции / символы, отмеченные __attribute__ ((visibility ("default")))
, являются внешними в результирующем общем объекте.
Вы можете проверить, являются ли символы, которые вы ищете, внешними, вызвав:
# -D shows (global) dynamic symbols that can be used from the outside of XXX.so
nm -D XXX.so | grep MY_SYMBOL
скрытые / локальные символы показаны как nm
с типом символов в нижнем регистре, например t
вместо `T для секции кода:
nm XXX.so
00000000000005a7 t HIDDEN_SYMBOL
00000000000005f8 T VISIBLE_SYMBOL
Вы также можете использовать nm
с опцией -C
для разборки имен (если использовался C ++).
Подобно Windows-DLL, можно было бы пометить публичные функции определением, например DLL_PUBLIC
, определенным как:
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
DLL_PUBLIC int my_public_function(){
...
}
, что примерно соответствует версии Windows / MSVC:
#ifdef BUILDING_DLL
#define DLL_PUBLIC __declspec(dllexport)
#else
#define DLL_PUBLIC __declspec(dllimport)
#endif
Больше информации о видимости можно найти в gcc wiki.
Когда модуль перевода скомпилирован с -fvisibility=hidden
, результирующие символы все еще имеют внешнюю связь (показана с символом верхнего регистра в виде nm
) и могут без проблем использоваться для внешней связи, если объектные файлы становятся частью статических библиотек. Связь становится локальной, только когда объектные файлы связаны в общей библиотеке.
Чтобы найти, какие символы в объектном файле скрыты, выполните:
>>> objdump -t XXXX.o | grep hidden
0000000000000000 g F .text 000000000000000b .hidden HIDDEN_SYMBOL1
000000000000000b g F .text 000000000000000b .hidden HIDDEN_SYMBOL2
Также, если вы используете сторонние библиотеки, убедитесь, что у вас есть правильные 32/64-битные двоичные файлы
Неспециализированные шаблоны должны иметь свои определения, видимые для всех единиц перевода, которые их используют. Это означает, что вы не можете отделить определение шаблона от файла реализации. Если вы должны отделить реализацию, обычный обходной путь должен иметь файл impl
, который вы включаете в конец заголовка, который объявляет шаблон. Типичная ситуация:
template<class T>
struct X
{
void foo();
};
int main()
{
X<int> x;
x.foo();
}
//differentImplementationFile.cpp
template<class T>
void X<T>::foo()
{
}
Чтобы исправить это, вы должны переместить определение X::foo
в файл заголовка или в какое-то место, видимое для единицы перевода, которая его использует.
Специализированные шаблоны могут быть реализованы в файле реализации, и реализация не должна быть видимой, но специализация должна быть предварительно объявлена.
Дальнейшее объяснение и другое возможное решение (явная реализация) см. В на этот вопрос и ответ .
Предположим, у вас есть большой проект, написанный на c ++, который имеет тысячу файлов .cpp и тысячу файлов .h. И давайте скажем, что проект также зависит от десяти статических библиотек. Допустим, мы находимся на Windows, и мы строим наш проект в Visual Studio 20xx. Когда вы нажимаете Ctrl + F7 Visual Studio, чтобы начать компиляцию всего решения (предположим, у нас есть только один проект в решении)
В чем смысл компиляции?
Второй шаг компиляции выполняется Linker.Linker должен объединить весь объектный файл и, наконец, создать вывод (который может быть исполняемым файлом или библиотекой)
Steps In Linking проект
error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)
Наблюдение ]
Как устранить эту ошибку
Ошибка времени компиляции:
Ошибка времени компоновщика
#pragma once
, чтобы компилятор не включал один заголовок, если он был уже включены в текущий .cpp, который скомпилирован Порядок, в котором связаны библиотеки, имеет значение, если библиотеки зависят друг от друга. В общем, если библиотека A
зависит от библиотеки B
, то libA
ДОЛЖНЫ появляться перед libB
в флагах компоновщика.
Например:
// B.h
#ifndef B_H
#define B_H
struct B {
B(int);
int x;
};
#endif
// B.cpp
#include "B.h"
B::B(int xx) : x(xx) {}
// A.h
#include "B.h"
struct A {
A(int x);
B b;
};
// A.cpp
#include "A.h"
A::A(int x) : b(x) {}
// main.cpp
#include "A.h"
int main() {
A a(5);
return 0;
};
Создать библиотеки:
$ g++ -c A.cpp
$ g++ -c B.cpp
$ ar rvs libA.a A.o
ar: creating libA.a
a - A.o
$ ar rvs libB.a B.o
ar: creating libB.a
a - B.o
Скомпилировать:
$ g++ main.cpp -L. -lB -lA
./libA.a(A.o): In function `A::A(int)':
A.cpp:(.text+0x1c): undefined reference to `B::B(int)'
collect2: error: ld returned 1 exit status
$ g++ main.cpp -L. -lA -lB
$ ./a.out
Итак, повторить еще раз, порядок DOES важно!
Как правило, каждая единица перевода генерирует объектный файл, который содержит определения символов, определенных в этой единице перевода. Чтобы использовать эти символы, вы должны ссылаться на эти объектные файлы.
В разделе gcc вы должны указать все объектные файлы, которые должны быть связаны вместе в командной строке, или скомпилировать файлы реализации вместе.
g++ -o test objectFile1.o objectFile2.o -lLibraryName
libraryName
здесь - просто голое название библиотеки, без специфических для платформы дополнений. Так, например в Linux файлы библиотеки обычно называются libfoo.so
, но вы должны написать только -lfoo
. В Windows этот же файл может называться foo.lib
, но вы будете использовать тот же аргумент. Возможно, вам придется добавить каталог, где эти файлы могут быть найдены с помощью -L‹directory›
. Убедитесь, что после -l
или -L
не написали пробел.
Для XCode : добавьте пути поиска по заголовку пользователя -> добавьте путь поиска по библиотеке -> перетащите фактическую ссылку на библиотеку в папку проекта.
В соответствии с MSVS , файлы, добавленные в проект, автоматически связывают свои объектные файлы, и создается файл lib
(в обычном использовании). Чтобы использовать символы в отдельном проекте, вам необходимо включить файлы lib
в настройки проекта. Это сделано в разделе Linker свойств проекта, в Input -> Additional Dependencies
. (путь к файлу lib
должен быть добавлен в Linker -> General -> Additional Library Directories
) При использовании сторонней библиотеки, которая поставляется с файлом lib
, невыполнение этого обычно приводит к ошибке.
Может также случиться, что вы забудете добавить файл в компиляцию, и в этом случае объектный файл не будет сгенерирован. В gcc вы добавляете файлы в командную строку. В MSVS добавление файла в проект заставит его автоматически скомпилировать его (хотя файлы можно вручную исключить из сборки по отдельности).
В программировании Windows контрольным признаком того, что вы не связали необходимую библиотеку, является то, что имя неразрешенного символа начинается с __imp_
. Посмотрите название функции в документации, и там должно быть указано, какую библиотеку вам нужно использовать. Например, MSDN помещает информацию в поле внизу каждой функции в разделе «Библиотека».